Skip to content

Commit b4b5d84

Browse files
committedDec 4, 2018
Lua backend for OpenWRT added.
1 parent 032b321 commit b4b5d84

File tree

6 files changed

+654
-0
lines changed

6 files changed

+654
-0
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
config filemanager 'config'
3+
option basedir '/mnt'
4+
option tmpdir '/tmp'
+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
-- cgi util module
2+
3+
local uci = require("uci")
4+
local u_c = uci.cursor()
5+
local tmppath = u_c.get("filemanager","config","tmpdir")
6+
7+
local prevbuf = ""
8+
local blocksize = 4096
9+
local _M = {}
10+
11+
_M.statusmsg = {
12+
[200] = "OK",
13+
[206] = "Partial Content",
14+
[301] = "Moved Permanently",
15+
[302] = "Found",
16+
[304] = "Not Modified",
17+
[400] = "Bad Request",
18+
[403] = "Forbidden",
19+
[404] = "Not Found",
20+
[405] = "Method Not Allowed",
21+
[408] = "Request Time-out",
22+
[411] = "Length Required",
23+
[412] = "Precondition Failed",
24+
[416] = "Requested range not satisfiable",
25+
[500] = "Internal Server Error",
26+
[503] = "Server Unavailable",
27+
}
28+
29+
-- call this function passing an empy table. use that table for successive calls.
30+
function _M.new(req)
31+
req.content_length = os.getenv("CONTENT_LENGTH")
32+
req.request_method = os.getenv("REQUEST_METHOD")
33+
if req.request_method == "POST" then
34+
req.content_type, req.boundary = string.match(os.getenv("CONTENT_TYPE"),"^(multipart/form%-data); boundary=\"?(.+)\"?$")
35+
req.boundary = "--" .. req.boundary
36+
end
37+
-- this is useful only if you have /tmp on tmpfs like in openwrt. otherwise can be set to ""
38+
req.tempdir = tmppath
39+
req.post = {}
40+
end
41+
42+
-- this function is needed to clean temp file since and hide implementation details
43+
function _M.cleanup(req)
44+
for k, v in pairs(req.post) do
45+
for j, v in pairs(req.post[k]) do
46+
if req.post[k][j].tempname then
47+
os.remove(req.post[k][j].tempname) -- if file unused
48+
os.remove("/tmp/" .. string.match(req.post[k][j].tempname,"^" .. req.tempdir .. "(.+)"))
49+
end
50+
end
51+
end
52+
end
53+
54+
-- del: delimiter
55+
-- return chunk (string), found (boolean)
56+
local function chunkread(del)
57+
local buf, found = 0
58+
local del = del or "\r\n"
59+
60+
buf = io.read(math.max(0,blocksize + #del - #prevbuf))
61+
if prevbuf ~= "" then buf = prevbuf .. ( buf or "" ); prevbuf = "" end
62+
if not buf then return end
63+
64+
s, e = string.find(buf,del,1,true)
65+
if s and e then
66+
found = 1
67+
prevbuf = string.sub(buf,e+1)
68+
buf = string.sub(buf,1,s-1)
69+
else
70+
prevbuf = string.sub(buf,math.min(blocksize,#buf)+1)
71+
buf = string.sub(buf,1,math.min(blocksize,#buf))
72+
end
73+
74+
return buf, found
75+
end
76+
77+
78+
function _M.parse_request_body (req)
79+
local chunk, found, type, tempname, tempfile
80+
local param = {}
81+
82+
-- read first boundary line
83+
chunk, found = chunkread(req.boundary)
84+
chunk, found = chunkread("\r\n")
85+
while chunk == "" do
86+
-- read part headers and get parameters value
87+
repeat
88+
chunk, found = chunkread("\r\n")
89+
if not found then return 400, "Malformed POST. Missing Part Header or Part Header too long." end
90+
string.gsub(chunk, ';%s*([^%s=]+)="(.-[^\\])"', function(k, v) param[k] = v end)
91+
param.type = param.type or string.match(chunk, "^Content%-Type: (.+)$")
92+
until chunk == ""
93+
94+
-- prepare file data read
95+
if not param.name then return 400, "Malformed POST. Check Header parameters." end
96+
param.size=0
97+
param.tempname = req.tempdir .. string.match(os.tmpname(), "^/tmp(.+)")
98+
tempfile = io.open(param.tempname, "w")
99+
100+
-- read part body content until boundary
101+
repeat
102+
chunk, found = chunkread("\r\n" .. req.boundary)
103+
if not chunk then return 400, "Malformed POST. Incomplete Part received." end
104+
tempfile:write(chunk)
105+
param.size = param.size + #chunk
106+
until found
107+
tempfile:close()
108+
req.post[param.name] = req.post[param.name] or {}
109+
table.insert(req.post[param.name], 1, param)
110+
param = {}
111+
112+
-- read after boundary. if CRLF ("") repeat. if "--" end POST processing
113+
chunk, found = chunkread("\r\n")
114+
end
115+
116+
if found and chunk == "--" then return 0, "OK" end
117+
return 400, "Malformed POST. Boundary not properly ended with CRLF or --."
118+
end
119+
120+
return _M
+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#!/usr/bin/lua
2+
3+
local uci = require "uci"
4+
local fs = require "nixio.fs"
5+
local u_c = uci.cursor()
6+
local basepath = u_c.get("filemanager","config","basedir")
7+
8+
local _M = {}
9+
10+
local bp = basepath:match("(.*)/")
11+
if bp and bp ~= "" then
12+
basepath = bp
13+
end
14+
_M.basepath = basepath;
15+
16+
function _M.is_in_dir(file, dir)
17+
if file == dir then
18+
return true
19+
else
20+
return file:sub(1, #dir) == dir
21+
end
22+
end
23+
24+
function _M.path_valid(path)
25+
return _M.is_in_dir(path,_M.basepath) and fs.access(path,"r")
26+
end
27+
28+
function _M.dir_path_valid(path)
29+
return _M.is_in_dir(path,_M.basepath) and fs.stat(path,"type")=="dir" and fs.access(path,"w")
30+
end
31+
32+
function _M.new_path_valid(path)
33+
local dirpath = fs.dirname(path)
34+
return _M.is_in_dir(dirpath,_M.basepath) and fs.access(dirpath,"w")
35+
end
36+
37+
function _M.make_path(path)
38+
local realpath = fs.realpath(_M.basepath..'/'..path)
39+
if _M.path_valid(realpath) then
40+
return realpath
41+
else
42+
return nil
43+
end
44+
end
45+
46+
function _M.make_new_path(path)
47+
local realpath = fs.realpath(fs.dirname(_M.basepath..'/'..path))..'/'..fs.basename(path)
48+
if _M.new_path_valid(realpath) then
49+
return realpath
50+
else
51+
return nil
52+
end
53+
end
54+
55+
function _M.make_dir_path(path)
56+
local realpath = fs.realpath(_M.basepath..'/'..path)
57+
if _M.dir_path_valid(realpath) then
58+
return realpath
59+
else
60+
return nil
61+
end
62+
end
63+
64+
function _M.rm(item)
65+
local ftype = fs.stat(item,"type")
66+
if ftype == "reg" then
67+
return fs.remove(item)
68+
elseif ftype == "dir" then
69+
local dir = fs.dir(item)
70+
for file in dir do
71+
if not _M.rm(item..'/'..file) then
72+
return false
73+
end
74+
end
75+
return fs.rmdir(item)
76+
else
77+
return false
78+
end
79+
end
80+
81+
function _M.chmod(item,mode,recursive)
82+
local result = fs.chmod(item,mode)
83+
if result and recursive then
84+
local dir = fs.dir(item)
85+
if dir then
86+
for file in dir do
87+
local ftype = fs.stat(item..'/'..file,"type")
88+
if ftype == "dir" then
89+
result = _M.chmod(item..'/'..file,mode,recursive)
90+
elseif ftype == "reg" then
91+
result = _M.chmod(item..'/'..file,string.gsub(mode,"x","-"),false)
92+
end
93+
if not result then
94+
break
95+
end
96+
end
97+
end
98+
end
99+
return result
100+
end
101+
102+
return _M

‎bridges/openwrt-lua/www/cgi-bin/fs

+359
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,359 @@
1+
#!/usr/bin/lua
2+
3+
local os = require "os"
4+
local fs = require "nixio.fs"
5+
local json = require "json"
6+
local luafm = require("luafm")
7+
8+
print("Content-type: text/html; charset=utf-8")
9+
print("Cache-control: no-cache")
10+
print("Pragma: no-cache")
11+
12+
-- prepare the browser for content:
13+
print("\r")
14+
15+
local result
16+
17+
local http_headers = nixio.getenv()
18+
local request=io.read("*all")
19+
20+
local params=json.decode(request)
21+
local action=params["action"]
22+
23+
local path
24+
local items
25+
local item
26+
local newItemPath
27+
local newPath
28+
local singleFilename
29+
local content
30+
local mode
31+
local destination
32+
local compressedFilename
33+
local recursive
34+
local folderName
35+
36+
local files
37+
local fstat
38+
local ftype
39+
local basename
40+
local realitem
41+
local command
42+
43+
if action == "list" then
44+
45+
path = luafm.make_path(params["path"])
46+
47+
if path then
48+
files = {}
49+
local rec
50+
for name in fs.dir(path) do
51+
basename=fs.realpath(path..'/'..name)
52+
if basename then
53+
fstat=fs.stat(basename)
54+
if fstat["type"]=="reg" then
55+
ftype="file"
56+
elseif fstat["type"]=="dir" then
57+
ftype="dir"
58+
else
59+
ftype=""
60+
end
61+
if ftype then
62+
rec={name=name,rights=fstat["modestr"],size=fstat["size"],type=ftype,date=os.date('%Y-%m-%d %H:%M:%S',fstat["mtime"])}
63+
table.insert(files,rec)
64+
end
65+
end
66+
end
67+
result = { result = files }
68+
else
69+
result = { result = {} }
70+
end
71+
72+
elseif action == "rename" then
73+
74+
item = luafm.make_path(params["item"])
75+
newItemPath = luafm.make_new_path(params["newItemPath"])
76+
77+
if item and newItemPath and item ~= luafm.basepath and newItemPath ~= luafm.basepath then
78+
result = fs.rename(item,newItemPath)
79+
if result then
80+
result = { result = { success=true, error="" } }
81+
else
82+
result = { result = { success=false, error="Cannot rename requested file/directory" } }
83+
end
84+
else
85+
result = { result = { success=false, error="Invalid path request" } }
86+
end
87+
88+
elseif action == "move" then
89+
90+
items = params["items"]
91+
newPath = luafm.make_dir_path(params["newPath"])
92+
93+
if newPath then
94+
95+
result = true
96+
97+
for key,item in pairs(items) do
98+
99+
item = luafm.make_path(item)
100+
101+
if item and item ~= luafm.basepath then
102+
basename = fs.basename(item)
103+
result = fs.move(item,newPath.."/"..basename)
104+
if not result then
105+
break
106+
end
107+
else
108+
result = false
109+
break
110+
end
111+
112+
end
113+
114+
if result then
115+
result = { result = { success=true, error="" } }
116+
else
117+
result = { result = { success=false, error="Cannot move requested file/directory" } }
118+
end
119+
120+
else
121+
122+
result = { result = { success=false, error="Invalid destination request" } }
123+
124+
end
125+
126+
elseif action == "copy" then
127+
128+
items = params["items"]
129+
newPath = luafm.make_dir_path(params["newPath"])
130+
131+
if newPath then
132+
133+
singleFilename = params["singleFilename"]
134+
if singleFilename then
135+
singleFilename = fs.basename(singleFilename)
136+
end
137+
138+
result = true
139+
140+
for key,item in pairs(items) do
141+
142+
item = luafm.make_path(item)
143+
144+
if item and item ~= luafm.basepath then
145+
if singleFilename then
146+
basename = singleFilename
147+
else
148+
basename = fs.basename(item)
149+
end
150+
result = fs.copy(item,newPath.."/"..basename)
151+
if not result then
152+
break
153+
end
154+
else
155+
result = false
156+
break
157+
end
158+
159+
end
160+
161+
if result then
162+
result = { result = { success=true, error="" } }
163+
else
164+
result = { result = { success=false, error="Cannot copy requested file/directory" } }
165+
end
166+
167+
else
168+
169+
result = { result = { success=false, error="Invalid destination request" } }
170+
171+
end
172+
173+
elseif action == "remove" then
174+
175+
items = params["items"]
176+
177+
result = true
178+
179+
for key,item in pairs(items) do
180+
181+
item = luafm.make_path(item)
182+
183+
if item and item ~= luafm.basepath then
184+
result = luafm.rm(item)
185+
if not result then
186+
break
187+
end
188+
else
189+
result = false
190+
break
191+
end
192+
193+
end
194+
195+
if result then
196+
result = { result = { success=true, error="" } }
197+
else
198+
result = { result = { success=false, error="Cannot remove requested file/directory" } }
199+
end
200+
201+
elseif action == "getContent" then
202+
203+
item = luafm.make_path(params["item"])
204+
205+
if item and item ~= luafm.basepath then
206+
content = fs.readfile(item)
207+
result = { result = content }
208+
else
209+
result = { result = { success=false, error="Invalid path request" } }
210+
end
211+
212+
elseif action == "edit" then
213+
214+
item = luafm.make_path(params["item"])
215+
content = params["content"]
216+
217+
if item and item ~= luafm.basepath then
218+
result = fs.writefile(item,content)
219+
if result then
220+
result = { result = { success=true, error="" } }
221+
else
222+
result = { result = { success=false, error="Cannot write requested file content" } }
223+
end
224+
else
225+
result = { result = { success=false, error="Invalid path request" } }
226+
end
227+
228+
elseif action == "createFolder" then
229+
230+
newPath = luafm.make_new_path(params["newPath"])
231+
232+
if newPath and newPath ~= luafm.basepath then
233+
result = fs.mkdir(newPath)
234+
if result then
235+
result = { result = { success=true, error="" } }
236+
else
237+
result = { result = { success=false, error="Cannot create folder" } }
238+
end
239+
else
240+
result = { result = { success=false, error="Invalid path request" } }
241+
end
242+
243+
elseif action == "changePermissions" then
244+
245+
items = params["items"]
246+
247+
if params["perms"] then
248+
mode = params["perms"]
249+
else
250+
mode = params["permsCode"]
251+
end
252+
253+
if mode then
254+
255+
recursive = params["recursive"]
256+
257+
result = true
258+
259+
for key,item in pairs(items) do
260+
261+
item = luafm.make_path(item)
262+
263+
if item and item ~= luafm.basepath then
264+
result = luafm.chmod(item,mode,recursive)
265+
if not result then
266+
break
267+
end
268+
else
269+
result = false
270+
break
271+
end
272+
273+
end
274+
275+
if result then
276+
result = { result = { success=true, error="" } }
277+
else
278+
result = { result = { success=false, error="Cannot change permissions" } }
279+
end
280+
281+
else
282+
283+
result = { result = { success=false, error="No permission requested" } }
284+
285+
end
286+
287+
elseif action == "compress" then
288+
289+
items = params["items"]
290+
destination = params["destination"]
291+
compressedFilename = params["compressedFilename"]
292+
293+
newPath = luafm.make_new_path(destination..'/'..fs.basename(params["compressedFilename"]))
294+
295+
result = true
296+
files = ""
297+
298+
for key,item in pairs(items) do
299+
300+
realitem = luafm.make_path(item)
301+
302+
if realitem and realitem ~= luafm.basepath then
303+
item = item:match("/(.*)")
304+
files = files.." "..item
305+
else
306+
result = false
307+
break
308+
end
309+
310+
end
311+
312+
if files then
313+
314+
command = "cd "..luafm.basepath.."; zip -r "..newPath..files
315+
result = os.execute(command)
316+
317+
if result then
318+
result = { result = { success=true, error="" } }
319+
else
320+
result = { result = { success=false, error="Archiver returned error" } }
321+
end
322+
323+
else
324+
325+
result = { result = { success=false, error="No files selected" } }
326+
327+
end
328+
329+
elseif action == "extract" then
330+
331+
item = luafm.make_path(params["item"])
332+
destination = params["destination"]
333+
folderName = params["folderName"]
334+
335+
newPath = luafm.make_new_path(destination..'/'..fs.basename(params["folderName"]))
336+
337+
result = true
338+
files = ""
339+
340+
if item and newPath and item ~= luafm.basepath then
341+
command = "unzip "..item.." -d "..newPath
342+
result = os.execute(command)
343+
if result then
344+
result = { result = { success=true, error="" } }
345+
else
346+
result = { result = { success=false, error="Archiver returned error" } }
347+
end
348+
else
349+
result = { result = { success=false, error="Invalid path request" } }
350+
end
351+
352+
353+
else
354+
355+
result = { result = { success=false, error="Operation not impolemented yet" } }
356+
357+
end
358+
359+
print(json.encode(result))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/usr/bin/lua
2+
3+
nixio = require "nixio"
4+
fs = require "nixio.fs"
5+
util = require "luci.util"
6+
ltn12 = require "ltn12"
7+
luafm = require "luafm"
8+
9+
args = {}
10+
11+
for dummy,param in pairs(util.split(nixio.getenv('QUERY_STRING'),'&')) do
12+
val = util.split(param,'=')
13+
args[val[1]] = util.urldecode(val[2],true)
14+
end
15+
16+
path = luafm.make_path(args["path"])
17+
if path then
18+
file = io.open(path,"rb")
19+
else
20+
file = nil
21+
end
22+
23+
if file then
24+
print("Content-Type: application/octet-stream")
25+
print('Content-Disposition: attachment; filename="'..fs.basename(args["path"])..'"')
26+
print("\r")
27+
ltn12.pump.all(
28+
ltn12.source.file(file),
29+
ltn12.sink.file(io.stdout)
30+
)
31+
else
32+
print("Status: 404 Not Found")
33+
print("Content-Type: text/plain")
34+
print("\r")
35+
print("File not found")
36+
end
+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!/usr/bin/lua
2+
3+
local cgi = require "cgi"
4+
local fs = require "nixio.fs"
5+
local luafm = require "luafm"
6+
7+
local req = {}
8+
9+
print("\r")
10+
11+
cgi.new(req)
12+
13+
if req.boundary then
14+
ret, msg = cgi.parse_request_body(req)
15+
end
16+
17+
destfile=io.open(req.post["destination"][1]["tempname"],"r")
18+
destination=destfile:read("*all")
19+
20+
for k, v in pairs(req.post) do
21+
for j, v in pairs(req.post[k]) do
22+
if v["filename"] then
23+
path = luafm.make_new_path(destination..'/'..v.filename)
24+
if path then
25+
fs.copy(req.post[k][j].tempname, path)
26+
end
27+
end
28+
end
29+
end
30+
31+
cgi.cleanup(req)
32+
33+
print('{ "result": { "success": true, "error": null } }')

0 commit comments

Comments
 (0)
Please sign in to comment.