Advertisement
immibis

rfs-server

Aug 4th, 2013
101
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 5.65 KB | None | 0 0
  1. os.pullEvent = os.pullEventRaw
  2. os.loadAPI("/md5")
  3.  
  4. local args = {...}
  5.  
  6. local cfgfile = "/rfs-sv.cfg"
  7.  
  8. local prefix
  9.  
  10. local senders = {}
  11.  
  12. local function loadConfig()
  13.     local f = fs.open(cfgfile, "r")
  14.     if f == nil then return end
  15.     f.readLine() -- unused
  16.     f.readLine() -- unused
  17.     prefix = f.readLine()
  18.     f.close()
  19.  
  20.     if fs.exists("/idlist") then
  21.         local fn = assert(loadfile("/idlist"))
  22.         senders = {}
  23.         setfenv(fn, senders)
  24.         fn()
  25.         if prefix then
  26.             fs.delete(prefix.."/ids")
  27.             fs.copy("/idlist", prefix.."/ids")
  28.         end
  29.     end
  30.  
  31.     return prefix ~= nil
  32. end
  33.  
  34. local function prompt(str)
  35.     write(str)
  36.     return read()
  37. end
  38.  
  39. local function newConfig()
  40.     prefix = prefix or prompt("Prefix: ")
  41.  
  42.     local f = fs.open(cfgfile, "w")
  43.     f.writeLine("")
  44.     f.writeLine("")
  45.     f.writeLine(prefix)
  46.     f.close()
  47. end
  48.  
  49. if #args >= 1 then
  50.     local mode = args[1]
  51.     if mode == "config" or mode == "reconfig" then
  52.         if mode == "config" then
  53.             loadConfig()
  54.         end
  55.         newConfig()
  56.         return
  57.     end
  58. end
  59.  
  60. if not loadConfig() then
  61.     print("Server not fully configured (config file "..cfgfile..")")
  62.     print("To configure, use")
  63.     print("  "..shell.getRunningProgram().." config")
  64.     print("To configure from scratch, erasing any existing settings, use")
  65.     print("  "..shell.getRunningProgram().." reconfig")
  66.     return
  67. end
  68.  
  69. for _,v in ipairs(redstone.getSides()) do
  70.     if peripheral.getType(v) == "modem" then
  71.         rednet.open(v)
  72.     end
  73. end
  74.  
  75. local nextHandle = 0
  76. local handles = {}
  77. local handleAuth = {}
  78.  
  79. -- verify path, return fixed path or raise error
  80. local function path(p)
  81.     if type(p) ~= "string" then error("expected string, got "..tostring(p)) end
  82.     p = p:gsub("\\","/")
  83.     if p:sub(1,1) ~= "/" then error("path must start with slash") end
  84.     if (p.."/"):find("/%.%./") then error("path may not use ..") end
  85.     return p
  86. end
  87.  
  88. local function allowsType(granted, requested)
  89.     if granted == "rw" then
  90.         return requested == "ro" or requested == "rw"
  91.     elseif granted == "ro" then
  92.         return requested == "ro"
  93.     else
  94.         return false
  95.     end
  96. end
  97.  
  98. local function checkAuth(sender, path, type)
  99.     do return true end -- Disable authentication
  100.  
  101.     sender = "_" .. sender
  102.     if not senders[sender] then
  103.         return false
  104.     end
  105.     local matches = senders[sender].rfs2 or {}
  106.     matches["/"] = senders[sender].rfs
  107.     local longest, longestLength = nil, 0
  108.     for k,v in pairs(matches) do
  109.         if path:sub(1, k:len()) == k and k:len() > longestLength then
  110.             longest = k
  111.             longestLength = k:len()
  112.         end
  113.     end
  114.     return allowsType(matches[longest], type)
  115. end
  116.  
  117. local function assertAuth(sender, path, type)
  118.     if not checkAuth(sender, path, type) then
  119.         if type == "rw" and checkAuth(sender, path, "ro") then error("Read-only filesystem", 0) end
  120.         error("Acccess denied.", 0)
  121.     end
  122. end
  123.  
  124. local function process(sender, t)
  125.     local level = senders["_"..sender] and senders["_"..sender].rfs -- or getMatchLevel(t[2])
  126.     if not level then return end
  127.     local readonly = level == "ro"
  128.  
  129.     local seq, cmd = t[3], t[4]
  130.     local reply = function(...)
  131.         rednet.send(sender, textutils.serialize({"RFS", seq, ...}))
  132.     end
  133.     if cmd == "isReadOnly" then
  134.         if not checkAuth(sender, t[5], "rw") then
  135.             reply(true)
  136.         else
  137.             reply(fs.isReadOnly(prefix..path(t[5])))
  138.         end
  139.     elseif cmd == "exists" then
  140.         assertAuth(sender, t[5], "ro")
  141.         reply(fs.exists(prefix..path(t[5])))
  142.     elseif cmd == "isDir" then
  143.         assertAuth(sender, t[5], "ro")
  144.         reply(fs.isDir(prefix..path(t[5])))
  145.     elseif cmd == "list" then
  146.         assertAuth(sender, t[5], "ro")
  147.         reply(unpack(fs.list(prefix..path(t[5]))))
  148.     elseif cmd == "getDrive" then
  149.         assertAuth(sender, t[5], "ro")
  150.         reply(fs.getDrive(prefix..path(t[5])))
  151.     elseif cmd == "mkdir" then
  152.         assertAuth(sender, t[5], "rw")
  153.         reply(fs.makeDir(prefix..path(t[5])))
  154.     elseif cmd == "delete" then
  155.         assertAuth(sender, t[5], "rw")
  156.         reply(fs.delete(prefix..path(t[5])))
  157.     elseif cmd == "getSize" then
  158.         assertAuth(sender, t[5], "ro")
  159.         reply(fs.getSize(prefix..path(t[5])))
  160.     elseif cmd == "getFreeSpace" then
  161.         assertAuth(sender, t[5], "ro")
  162.         reply(fs.getFreeSpace(prefix..t[5]))
  163.     elseif cmd == "open" then
  164.         if t[6] ~= "r" and t[6] ~= "rb" then
  165.             assertAuth(sender, t[5], "rw")
  166.         else
  167.             assertAuth(sender, t[5], "ro")
  168.         end
  169.         local id = nextHandle
  170.         handles[id] = fs.open(prefix..path(t[5]), t[6])
  171.         if handles[id] == nil then
  172.             reply(nil)
  173.         else
  174.             nextHandle = nextHandle + 1
  175.             handleAuth[id] = sender
  176.             reply(id)
  177.         end
  178.     elseif cmd == "readLine" then
  179.         if handleAuth[t[5]] ~= sender then error("Invalid handle") end
  180.         reply(handles[t[5]].readLine())
  181.     elseif cmd == "readAll" then
  182.         if handleAuth[t[5]] ~= sender then error("Invalid handle") end
  183.         reply(handles[t[5]].readAll())
  184.     elseif cmd == "write" then
  185.         if handleAuth[t[5]] ~= sender then error("Invalid handle") end
  186.         reply(handles[t[5]].write(t[6]))
  187.     elseif cmd == "writeLine" then
  188.         if handleAuth[t[5]] ~= sender then error("Invalid handle") end
  189.         reply(handles[t[5]].writeLine(t[6]))
  190.     elseif cmd == "close" then
  191.         if handleAuth[t[5]] ~= sender then error("Invalid handle") end
  192.         reply(handles[t[5]].close())
  193.         handles[t[5]] = nil
  194.         handleAuth[t[5]] = nil
  195.     elseif cmd == "read" then
  196.         if handleAuth[t[5]] ~= sender then error("Invalid handle") end
  197.         reply(handles[t[5]].read())
  198.     else
  199.         error("Unknown RFS command "..cmd)
  200.     end
  201. end
  202.  
  203. while true do
  204.     local s, m = rednet.receive()
  205.     local ok, t = pcall(textutils.unserialize, m)
  206.     --print(m)
  207.     if ok and type(t) == "table" and t[1] == "RFS" then
  208.         local o = t[2]
  209.         t[2] = "*"
  210.         print(s," ",table.concat(t, " "))
  211.         t[2] = o
  212.  
  213.         local ok, err = pcall(process, s, t)
  214.         if not ok then
  215.             print("Error processing: " .. err)
  216.             rednet.send(sender, textutils.serialize({"RFS-error", t[3], err}))
  217.         end
  218.     end
  219. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement