-
Notifications
You must be signed in to change notification settings - Fork 0
/
init.lua
124 lines (98 loc) · 3.55 KB
/
init.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
local fs = require('fs')
local path = require('path')
local table = require('table')
local parseUrl = require('url').parse
local decodeURI = require('querystring').urldecode
function _filter (tbl, fn)
local result = {}
if not tbl or type(tbl) ~= 'table' then return result end
for key, value in pairs(tbl) do
if fn(value, key, tbl) then
table.insert(result, value)
end
end
return result
end
-- serve directory listings with the given `root` path
-- options:
-- `hidden` - display hidden dot files, defaults to false
-- `filter` - apply custom filter function to files, defaults to false
function directory (root, options)
if not root then error('root is required') end
root = path.normalize(root)
return function (req, res, nxt)
if req.method ~= 'GET' and req.method ~= 'HEAD' then return nxt() end
options = options or {}
local function createDirStream (route)
fs.stat(route, function (err, stat)
if err then
if err.code == 'ENOENT' then
return nxt()
end
if err.code == 'ENOTDIR' and route:sub(#route) == '/' then
res:writeHead(302)
res:setHeader('Location', req.url:sub(1, #req.url - 1))
return res:finish()
end
return nxt(err)
end
if stat.type ~= 'directory' then
return nxt()
end
fs.readdir(route, function (err, files)
if err then
return nxt(err)
end
if not options.hidden then
files = _filter(files, function (row, i)
return '.' ~= row:sub(1, 1)
end)
end
if options.filter then
files = _filter(files, options.filter)
end
table.sort(files)
local css = [[
* { margin 0; padding: 0; border: 0; outline: none; }
body { margin: 0; padding: 80px 100px; font: 13px "Helvetica Neue", "Arial", sans-serif; background: #eaedf1; }
h1 { margin: 0; font-size: 22px; color: #343434; }
ul { margin: 25px auto; }
ul li { margin: 5px 0; list-style: none; }
a { color: #555; text-decoration: none; display: block; margin: 5px; width: 30%; height: 25px; line-height: 25px; text-indent: 8px; float: left; -webkit-border-radius: 5px; border-radius: 5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
a:focus, a:hover { background: #fff; color: #303030; }
]]
local html = {
'<!doctype html>',
'<html>',
'<head>',
'<title>' .. route .. '</title>',
'<style>' .. css .. '</style>',
'</head>',
'<body>',
'<h1>' .. route .. '</h1>',
'<ul><li><a href="../">..</a></li>'
}
for i, file in ipairs(files) do
html[#html + 1] =
'<li><a href="' .. file .. '">' .. file .. '</a></li>'
end
html[#html + 1] = '</ul></body></html>\n'
html = table.concat(html)
res:setHeader('Content-Type', 'text/html')
res:setHeader('Content-Length', #html)
res:finish(html)
end)
end)
end
local url = parseUrl(req.url)
local file = decodeURI(url.pathname)
local filePath = path.normalize(path.join(root, file))
-- forbidden malicious path
p(filePath, filePath:sub(1, #root), root)
if filePath:sub(1, #root) ~= root then
return nxt({status = 403, msg = 'Forbidden'})
end
createDirStream(filePath)
end
end
return directory