Added syntax selection

Also, the file is now 257 lines longs, including the final empty line. It's empty anyway, so it doesn't count ? Right ?
This commit is contained in:
Reuh 2016-12-11 17:38:21 +01:00
parent 5dc3c37eee
commit fd6578671b
3 changed files with 22 additions and 18 deletions

View file

@ -1,7 +1,8 @@
vrel 0.1.5 (wip): vrel 0.1.5 (wip):
- Doubled the default maximum lifetime (3 months -> 6 months). - Doubled the default maximum lifetime (3 months -> 6 months).
- Added an optional configuration file. - Added an optional configuration file.
- Added syntax setting per-paste (wip). - Added syntax setting per-paste.
- Sender IP storing should work with proxies.
- Various luacheck cleaning (a few potential bugs are fixed). It's still complaining about legit things tho. - Various luacheck cleaning (a few potential bugs are fixed). It's still complaining about legit things tho.
vrel 0.1.4: vrel 0.1.4:
- Now stores the sender's IP - Now stores the sender's IP

View file

@ -17,6 +17,10 @@ return {
defaultLifetime = 86400, -- 1 day defaultLifetime = 86400, -- 1 day
-- Maximal size of a request/paste -- Maximal size of a request/paste
requestMaxDataSize = 15728640, -- 15MB requestMaxDataSize = 15728640, -- 15MB
-- Pygments style name
pygmentsStyle = "monokai",
-- Extra CSS applied to syntax-highlighted blocks (with and without Pygments)
extraStyle = "*{color:#F8F8F2;background-color:#272822;margin:0px;}pre{color:#8D8D8A;}",
-- Request timeout -- Request timeout
timeout = 1, -- 1 second timeout = 1, -- 1 second
-- Debug mode -- Debug mode

View file

@ -1,7 +1,7 @@
#!/bin/lua #!/bin/lua
--- vrel v0.1.5: online paste service, in 256 lines of Lua (max line lenght = 256 but we shouldn't go this far if not needed). --- vrel v0.1.5: online paste service, in 256 lines of Lua (max line lenght = 256 but we shouldn't go this far if not needed).
-- This module requires LuaSocket 2.0.2, and debug mode requires LuaFileSystem 1.6.3. Install pygmentize for the optional syntax highlighting. -- This module requires LuaSocket 2.0.2, and debug mode requires LuaFileSystem 1.6.3. Install pygmentize for the optional syntax highlighting. If you want persistance for paste storage, install lsqlite3. vrel should work with Lua 5.1 to 5.3.
-- If you want persistance for paste storage, install lsqlite3. vrel should work with Lua 5.1 to 5.3. math.randomseed(os.time())
local hasConfigFile, config = pcall(dofile, "config.lua") if not hasConfigFile then config = {} end local hasConfigFile, config = pcall(dofile, "config.lua") if not hasConfigFile then config = {} end
-- Basic HTTP server -- -- Basic HTTP server --
local httpd, requestMaxDataSize = nil, config.requestMaxDataSize or 15728640 -- max post/paste data size (bytes) (15MB) local httpd, requestMaxDataSize = nil, config.requestMaxDataSize or 15728640 -- max post/paste data size (bytes) (15MB)
@ -28,9 +28,8 @@ httpd = {
post = {}, -- POST args {argName=argValue,...} (strings) post = {}, -- POST args {argName=argValue,...} (strings)
get = {} -- GET args {argName=argValue,...} (strings) get = {} -- GET args {argName=argValue,...} (strings)
} }
-- Get headers data from socket local lines = {} -- Headers
local lines = {} repeat -- Get headers data from socket
repeat
local message = client:receive("*l") local message = client:receive("*l")
table.insert(lines, message) table.insert(lines, message)
until not message or #message == 0 until not message or #message == 0
@ -174,6 +173,7 @@ local function generateName(size) -- generate a paste name. If size ~= nil, will
until (not size and not (data[name] or forbiddenName[name])) or (#name >= (size or math.huge)) until (not size and not (data[name] or forbiddenName[name])) or (#name >= (size or math.huge))
return name return name
end end
local function getClientId(request) return request.headers["X-Forwarded-For"] or request.client:getpeername() end -- returns some identifier for the client who sent the request
local lastClean, cleanInterval = os.time(), config.cleanInterval or 1800 -- last clean time (all time are stored in seconds) and clean interval (30min) local lastClean, cleanInterval = os.time(), config.cleanInterval or 1800 -- last clean time (all time are stored in seconds) and clean interval (30min)
local maxLifetime, defaultLifetime = config.maxLifetime or 15552000, config.defaultLifetime or 86400 -- maximum lifetime of a paste (6 month) and default (1 day) local maxLifetime, defaultLifetime = config.maxLifetime or 15552000, config.defaultLifetime or 86400 -- maximum lifetime of a paste (6 month) and default (1 day)
local function clean() -- clean the database each cleanInterval local function clean() -- clean the database each cleanInterval
@ -187,7 +187,7 @@ local function get(name, request) clean() -- get a paste (returns nil if non-exi
if data[name] then if data[name] then
local d = data[name] local d = data[name]
if d.expire < os.time() then data[name] = nil return end if d.expire < os.time() then data[name] = nil return end
if request.client:getpeername() ~= d.senderId and d.burnOnRead then data[name] = nil end -- burn on read (except if retrieved by original poster) if getClientId(request) ~= d.senderId and d.burnOnRead then data[name] = nil end -- burn on read (except if retrieved by original poster)
return d return d
end end
end end
@ -196,13 +196,13 @@ local function post(paste, request) clean() -- add a paste, will check data and
if paste.lifetime then paste.expire = os.time() + (tonumber(paste.lifetime) or defaultLifetime) end if paste.lifetime then paste.expire = os.time() + (tonumber(paste.lifetime) or defaultLifetime) end
paste.expire = math.min(tonumber(paste.expire) or os.time()+defaultLifetime, os.time()+maxLifetime) paste.expire = math.min(tonumber(paste.expire) or os.time()+defaultLifetime, os.time()+maxLifetime)
paste.burnOnRead = paste.burnOnRead == true paste.burnOnRead = paste.burnOnRead == true
paste.senderId = paste.senderId or request.client:getpeername() or "0.0.0.0" paste.senderId = paste.senderId or getClientId(request) or "unknown"
paste.syntax = (paste.syntax or "text"):lower():match("[a-z]*") paste.syntax = (paste.syntax or "text"):lower():match("[a-z]*")
paste.data = tostring(paste.data) paste.data = tostring(paste.data)
data[name] = paste data[name] = paste
return name, data[name] return name, data[name]
end end
local pygmentsStyle, extraStyle = "monokai", "*{color:#F8F8F2;background-color:#272822;margin:0px;}pre{color:#8D8D8A;}" -- pygments style name, extra css for highlighted blocks (also aply if no pygments) local pygmentsStyle, extraStyle = config.pygmentsStyle or "monokai", config.extraStyle or "*{color:#F8F8F2;background-color:#272822;margin:0px;}pre{color:#8D8D8A;}" -- pygments style name, extra css for highlighted blocks (also aply if no pygments)
local function highlight(paste, forceLexer) -- Syntax highlighting; should returns the code block, style and everything included local function highlight(paste, forceLexer) -- Syntax highlighting; should returns the code block, style and everything included
local source = assert(io.open("pygmentize.tmp", "w")) -- Lua can't at the same time write an read from a command, so we need to put one in a file local source = assert(io.open("pygmentize.tmp", "w")) -- Lua can't at the same time write an read from a command, so we need to put one in a file
source:write(paste.data) source:close() source:write(paste.data) source:close()
@ -220,11 +220,10 @@ httpd.start(config.address or "*", config.port or 8155, { -- Pages
["/([^/]*)"] = function(request, name) ["/([^/]*)"] = function(request, name)
if forbiddenName[name] then return end if forbiddenName[name] then return end
if request.method == "POST" and request.post.data then if request.method == "POST" and request.post.data then
name = post({ lifetime = (tonumber(request.post.lifetime) or defaultLifetime/3600)*3600, burnOnRead = request.post.burnOnRead == "on", data = request.post.data }, request) name = post({ lifetime = (tonumber(request.post.lifetime) or defaultLifetime/3600)*3600, burnOnRead = request.post.burnOnRead == "on", syntax = request.post.syntax, data = request.post.data }, request)
return { "303 See Other", {["Location"] = "/"..name}, "" } return { "303 See Other", {["Location"] = "/"..name}, "" }
end end
return { "200 OK", {["Content-Type"] = "text/html"}, [[<!DOCTYPE html> return { "200 OK", {["Content-Type"] = "text/html"}, [[<!DOCTYPE html><html><head><meta charset="utf-8"/><title>vrel</title></head>
<html><head><meta charset="utf-8"/><title>vrel</title></head>
<body>]]..(#name == 0 and [[ <body>]]..(#name == 0 and [[
<style> <style>
* { padding: 0em; margin: 0em; color: #F8F8F2; background-color: #000000; font-size: 0.95em; font-family: mono, sans; border-style: none; } * { padding: 0em; margin: 0em; color: #F8F8F2; background-color: #000000; font-size: 0.95em; font-family: mono, sans; border-style: none; }
@ -233,22 +232,22 @@ httpd.start(config.address or "*", config.port or 8155, { -- Pages
#topbar { margin: 0.45em 0.2em; height: 1.85em; background-color: #000000; } #topbar { margin: 0.45em 0.2em; height: 1.85em; background-color: #000000; }
#topbar #controls { padding: 0.5em; } #topbar #controls { padding: 0.5em; }
#topbar input { height: 2em; text-align: center; background-color: #383832; } #topbar input { height: 2em; text-align: center; background-color: #383832; }
#topbar input[name=lifetime] { width: 5em; } #topbar input[name=lifetime] { width: 5em; } #topbar input[name=burnOnRead] { vertical-align: middle; }
#topbar input[name=burnOnRead] { vertical-align: middle; } #topbar input[name=syntax] { width: 5.5em; }
#topbar input[type=submit] { cursor: pointer; width: 10em; } #topbar input[type=submit] { cursor: pointer; width: 10em; }
#topbar #vrel { font-size: 1.5em; float: right; } #topbar #vrel { font-size: 1.5em; float: right; }
</style> </style>
<form method="POST" action="/"> <form method="POST" action="/">
<div id="topbar"><span id="controls">expires in <input name="lifetime" type="number" min="1" max="]]..math.floor(maxLifetime/3600)..[[" value="]]..math.floor(defaultLifetime/3600).. <div id="topbar"><span id="controls">expires in <input name="lifetime" type="number" min="1" max="]]..math.floor(maxLifetime/3600)..[[" value="]]..math.floor(defaultLifetime/3600)..
[["/> hours (<input name="burnOnRead" type="checkbox"/>burn on read) <input type="submit" value="post"/></span><a id="vrel" href="/">vrel</a></div> [["/> hours (<input name="burnOnRead" type="checkbox"/>burn on read) <input name="syntax" type="text" placeholder="syntax"/> <input type="submit" value="post"/></span><a id="vrel" href="/">vrel</a></div>
<textarea name="data" required=true></textarea> <textarea name="data" required=true autofocus placeholder="paste your text here"></textarea>
</form>]] or highlight(get(name:match("^[^.]+"), request) or {data="paste not found"}, name:lower():match("%.([a-z]+)$")))..[[ </form>]] or highlight(get(name:match("^[^.]+"), request) or {data="paste not found",syntax="text"}, name:lower():match("%.([a-z]+)$")))..[[
</body></html>]] } </body></html>]] }
end, end,
["/g/(.+)"] = function(request, name) local d = get(name, request) return d and { "200 OK", {["Content-Type"] = "text"}, d.data } or nil end, ["/g/(.+)"] = function(request, name) local d = get(name, request) return d and { "200 OK", {["Content-Type"] = "text"}, d.data } or nil end,
["/p"] = function(request) ["/p"] = function(request)
if request.method == "POST" and request.post.data then if request.method == "POST" and request.post.data then
local name, paste = post({ lifetime = tonumber(request.post.lifetime) or defaultLifetime, burnOnRead = request.post.burnOnRead == "on", data = request.post.data }, request) local name, paste = post({ lifetime = tonumber(request.post.lifetime) or defaultLifetime, burnOnRead = request.post.burnOnRead == "on", syntax = request.post.syntax, data = request.post.data }, request)
return { "200 OK", {["Content-Type"] = "text/json"}, "{\"name\":\""..name.."\",\"lifetime\":"..paste.expire-os.time()..",\"burnOnRead\":"..tostring(paste.burnOnRead).."}\n" } return { "200 OK", {["Content-Type"] = "text/json"}, "{\"name\":\""..name.."\",\"lifetime\":"..paste.expire-os.time()..",\"burnOnRead\":"..tostring(paste.burnOnRead).."}\n" }
end end
end end