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:
parent
5dc3c37eee
commit
fd6578671b
3 changed files with 22 additions and 18 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
33
vrel.lua
33
vrel.lua
|
|
@ -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
|
||||||
|
|
|
||||||
Reference in a new issue