Advertisement
Chickenbreadlp

ccFTP (Rev1) [API]

Jun 5th, 2016
161
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 19.00 KB | None | 0 0
  1. --[[
  2.     MIT License
  3.  
  4.     Copyright © 2016 Chickenbreadlp
  5.  
  6.     Permission is hereby granted, free of charge, to any person obtaining a copy
  7.     of this software and associated documentation files (the "Software"), to deal
  8.     in the Software without restriction, including without limitation the rights
  9.     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10.     copies of the Software, and to permit persons to whom the Software is
  11.     furnished to do so, subject to the following conditions:
  12.  
  13.     The above copyright notice and this permission notice shall be included in all
  14.     copies or substantial portions of the Software.
  15.  
  16.     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17.     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19.     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20.     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21.     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22.     SOFTWARE.
  23. ]]
  24.  
  25.  -- GitHub File Downloader for Self-Suppling
  26. local function GITget(branch, file)
  27.     local response = http.get(
  28.         "https://raw.githubusercontent.com/Chickenbreadlp/ReboOSt/"..branch.."/"..textutils.urlEncode( file )
  29.     )
  30.  
  31.     if response then
  32.         local sResponse = response.readAll()
  33.         response.close()
  34.         return sResponse
  35.     else
  36.     end
  37. end
  38. local function GITdownload(branch, filename, sFile)
  39.     if fs.exists( sFile ) then
  40.         return
  41.     end
  42.  
  43.     local res = GITget(branch, filename)
  44.     if res then
  45.         local file = fs.open( sFile, "w" )
  46.         file.write( res )
  47.         file.close()
  48.     end
  49. end
  50.  
  51.  -- Pastebin Downloader for Self-Suppling
  52. local function PASget(paste)
  53.     local response = http.get(
  54.         "http://pastebin.com/raw/"..textutils.urlEncode( paste )
  55.     )
  56.  
  57.     if response then
  58.         local sResponse = response.readAll()
  59.         response.close()
  60.         return sResponse
  61.     else
  62.     end
  63. end
  64. local function PASdownload(paste, sFile)
  65.     if fs.exists( sFile ) then
  66.         return
  67.     end
  68.  
  69.     local res = PASget(paste)
  70.     if res then
  71.         local file = fs.open( sFile, "w" )
  72.         file.write( res )
  73.         file.close()
  74.     end
  75. end
  76.  
  77.  
  78.  -- Way to create a keypair for AES from single case-sensitive key for Server functions
  79. local function unfoldkeyS(keyhash)
  80.  math.randomseed(tonumber(keyhash, 36))
  81.  local key = {}
  82.  local iv = {}
  83.  for i=1, 16 do
  84.   key[i] = math.random(0, 0xFF)
  85.   iv[i] = math.random(0, 0xFF)
  86.  end
  87.  math.randomseed(os.clock())
  88.  return key, iv
  89. end
  90.  
  91.  -- Way to create a keypair for AES from single case-sensitive key for Clint functions
  92. local function unfoldkeyC(Key)
  93.  local keyhash = hash.sha256(Key)
  94.  math.randomseed(tonumber(keyhash, 36))
  95.  local key = {}
  96.  local iv = {}
  97.  for i=1, 16 do
  98.   key[i] = math.random(0, 0xFF)
  99.   iv[i] = math.random(0, 0xFF)
  100.  end
  101.  math.randomseed(os.clock())
  102.  return key, iv
  103. end
  104.  
  105.  
  106.  -- checks if needed APIs are available and (if not) do exist
  107. local function checkAPI()
  108.  if ccaes == nil then
  109.   if fs.exists("/.ccftp/ccaes") then
  110.    os.loadAPI("/.ccftp/ccaes")
  111.   else
  112.    PASdownload("rCYDnCxn", "/.ccftp/ccaes")
  113.    os.loadAPI("/.ccftp/ccaes")
  114.   end
  115.  end
  116.  if hash == nil then
  117.   if fs.exists("/.ccftp/hash") then
  118.    os.loadAPI("/.ccftp/hash")
  119.   else
  120.    GITdownload("release", "ReboOSt/APIs/encryption", "/.ccftp/hash")
  121.    os.loadAPI("/.ccftp/hash")
  122.   end
  123.  end
  124. end
  125.  
  126.  -- checks for a Modem
  127. local function checkModem()
  128.  if rednet.isOpen() then
  129.   return true
  130.  end
  131.  for _, side in ipairs( rs.getSides() ) do
  132.   if peripheral.isPresent( side ) and peripheral.getType( side ) == "modem" then
  133.    rednet.open( side )
  134.    return true
  135.   end
  136.  end
  137.  return false
  138. end
  139.  
  140.  
  141.  -- waits for receiving a message and unserialize it
  142. local function waitForMessage()
  143.  local senderID = nil
  144.  local command = nil
  145.  senderID, command = rednet.receive("ccFTP")
  146. -- command = textutils.unserialize(command)
  147.  return command, senderID
  148. end
  149.  
  150.  -- sendMessage function for Client tools
  151. local function sendMessageC(Hostname, UsrName, PassIV, command)
  152.  local command = { UsrName, PassIV, command }
  153. -- textutils.serialize(command)
  154.  local hostID = rednet.lookup("ccFTPhost", Hostname)
  155.  if hostID == nil then
  156.   return false
  157.  else
  158.   rednet.send(hostID, command, "ccFTP")
  159.   return hostID
  160.  end
  161. end
  162.  
  163.  -- sendMessage function for Server tools
  164. local function sendMessageS(response, ID)
  165. -- command = textutils.serialize(command)
  166.  rednet.send(ID, response, "ccFTP")
  167. end
  168.  
  169.  -- just a placeholder
  170. local runningHost = nil
  171.  
  172.  -- runs a FTP Server (Hostname sets the FTP-Server Name ; FtpDir sets the Directory which should be shared through ccFTP ; UsrDir sets the directory, where the Accounts will be saved)
  173.  -- It is not recommended to use Root Directory as FTP Share
  174. function runServer(Hostname, FtpDir, UsrDir)
  175.  
  176.  if Hostname == nil then
  177.   error("Hostname missing!")
  178.  end
  179.  
  180.  local UsrDir = UsrDir
  181.  local FtpDir = FtpDir
  182.  if UsrDir == nil then UsrDir = "/.ccftp/Users" end
  183.  if FtpDir == nil then FtpDir = "/FTP_Share" end
  184.  if not fs.exists(FtpDir) then fs.makeDir(FtpDir) end
  185.  
  186.  checkAPI()
  187.  
  188.  if checkModem() then
  189.   rednet.host("ccFTPhost", Hostname)
  190.   runningHost = Hostname
  191.   while(true) do
  192.    
  193.    local commandtab = nil
  194.    local sender = nil
  195.    commandtab, sender = waitForMessage()
  196.    
  197.    if #commandtab >= 3 then
  198.     if fs.exists(UsrDir.."/"..commandtab[1]) then
  199.    
  200.      local file = fs.open(UsrDir.."/"..commandtab[1], "r")
  201.      local pass = file.readLine()
  202.      file.close()
  203.      
  204.      local key, iv = unfoldkeyS(pass)
  205.      
  206.      if hash.sha256("iv"..iv[15]) == commandtab[2] then
  207.      
  208.       if commandtab[3][1] == "DirCont" then
  209.        if #commandtab[3] >= 2 then
  210.         if fs.exists(FtpDir.."/"..commandtab[3][2]) then
  211.          local DirCont = fs.list(FtpDir.."/"..commandtab[3][2])
  212.          local DirIdx = {}
  213.          for _, content in ipairs(DirCont) do
  214.           if fs.isDir(FtpDir.."/"..content) then
  215.            table.insert(DirIdx, content)
  216.           end
  217.          end
  218.          sendMessageS( { DirCont, DirIdx } , sender)
  219.         else
  220.          sendMessageS("ddne", sender)
  221.         end
  222.        else
  223.         sendMessageS("nea", sender)
  224.        end
  225.      
  226.       elseif commandtab[3][1] == "getFile" then
  227.        if #commandtab[3] >= 2 then
  228.         if fs.exists(FtpDir.."/"..commandtab[3][2]) and not fs.isDir(FtpDir.."/"..commandtab[3][2]) then
  229.          local file = fs.open(FtpDir.."/"..commandtab[3][2], "rb")
  230.          local fileData = {}
  231.          local filebyte = file.read()
  232.          repeat
  233.           table.insert(fileData, filebyte)
  234.           filebyte =file.read()
  235.          until filebyte == nil
  236.          file.close()
  237.          fileData = ccaes.encrypt_bytestream(fileData, key, iv)
  238.          local response = { hash.sha256("iv"..iv[16]), fileData }
  239.          sendMessageS(response, sender)
  240.         else
  241.          sendMessageS("fdne", sender)
  242.         end
  243.        else
  244.         sendMessageS("nea", sender)
  245.        end
  246.      
  247.       elseif commandtab[3][1] == "pushFile" then
  248.        if #commandtab[3] >= 3 then
  249.         local decdat = ccaes.decrypt_bytestream(commandtab[3][3], key, iv)
  250.         local file = fs.open(FtpDir.."/"..commandtab[3][2], "wb")
  251.         for i = 1, #decdat do
  252.          file.write(decdat[i])
  253.         end
  254.         file.close()
  255.         sendMessageS("OK", sender)
  256.        
  257.        else
  258.         sendMessageS("nea", sender)
  259.        end
  260.      
  261.       else
  262.        sendMessageS("nsc", sender)
  263.       end
  264.      
  265.      else
  266.       sendMessageS("pww", sender)
  267.      end
  268.    
  269.     else
  270.      sendMessageS("nsu", sender)
  271.     end
  272.    
  273.    else
  274.     sendMessageS("nea", sender)
  275.    end
  276.  
  277.   end
  278.  
  279.  else
  280.   error("No Modem attached!")
  281.  end
  282.  
  283. end
  284.  
  285.  
  286.  -- creates a new user (should only be run on ftp server) returns true when finishing succesfull; returns nUsrN when no user is specified; returns nUsrP when no Password is specified; returns UsrE when user already exists
  287. function createUser(UsrName, UsrPass, UsrDir)
  288.  checkAPI()
  289.  if UsrName == nil then return "nUsrN" end
  290.  if UsrPass == nil then return "nUsrP" end
  291.  local UsrDir = UsrDir or "/.ccftp/Users"
  292.  if fs.exists(UsrDir.."/"..UsrName) then return "UsrE" end
  293.  local file = fs.open(UsrDir.."/"..UsrName, "w")
  294.  file.writeLine(hash.sha256(UsrPass))
  295.  file.close()
  296.  return true
  297. end
  298.  
  299.  -- renames an already existing User (should only be run on ftp server) returns true when successfull; returns noUsrN when oUsrName not specified; returns nnUsrN when nUsrName not specified; returns nUsrP when UsrPass not specified; returns nsUsr when User does not exists; returns nUsrE when target name exists;returns pww when password wrong
  300. function renameUser(oUsrName, nUsrName, UsrPass, UsrDir)
  301.  checkAPI()
  302.  if oUsrName == nil then return "noUsrN" end
  303.  if nUsrName == nil then return "nnUsrN" end
  304.  if UsrPass == nil then return "nUsrP" end
  305.  local UsrDir = UsrDir or "/.ccftp/Users"
  306.  if not fs.exists(UsrDir.."/"..oUsrName) then return "nsUsr" end
  307.  if fs.exists(UsrDir.."/"..nUsrName) then return "nUsrE" end
  308.  local file = fs.open(UserDir.."/"..oUsrName, "r")
  309.  local opass = file.readLine()
  310.  file.close()
  311.  if opass == hash.sha256(UsrPass) then
  312.   fs.move(UsrDir.."/"..oUsrName, UsrDir.."/"..nUsrName)
  313.   return true
  314.  else
  315.   return "pww"
  316.  end
  317. end
  318.  
  319.  -- changes the password from any existing User (should only be run on ftp server) returns true when successfull; returns nUsrN when UsrName not specified; returns noUsrP when oUsrPass not specified; returns nnUsrP when nUsrPass not specified; returns nsUsr when User does not exists; returns pww when password wrong
  320. function changeUserPass(UsrName, oUsrPass, nUsrPass, UsrDir)
  321.  checkAPI()
  322.  if UsrName == nil then return "nUsrN" end
  323.  if oUsrPass == nil then return "noUsrP" end
  324.  if nUsrPass == nil then return "nnUsrP" end
  325.  local UsrDir = UsrDir or "/.ccftp/Users"
  326.  if not fs.exists(UsrDir.."/"..UsrName) then return "nsUsr" end
  327.  local file = fs.open(UsrDir.."/"..UsrName, "r")
  328.  local opass = file.readLine()
  329.  file.close()
  330.  if opass == hash.sha256(oUsrPass) then
  331.   local file = fs.open(UsrDir.."/"..UsrName, "w")
  332.   file.writeLine(hash.sha256(nUsrPass))
  333.   file.close()
  334.   return true
  335.  else
  336.   return "pww"
  337.  end
  338. end
  339.  
  340.  -- removes any given user (should only be run on ftp server) returns turn when successfull; returns nUsrN when UsrName not specified; returns nUsrP when UsrPass not specified; returns nsUsr when User does not exists; returns pww when password wrong
  341. function removeUser(UsrName, UsrPass, UsrDir)
  342.  checkAPI()
  343.  if UsrName == nil then return "nUsrN" end
  344.  if UsrPass == nil then return "nUsrP" end
  345.  local UsrDir = UsrDir or "/.ccftp/Users"
  346.  if not fs.exists(UsrDir.."/"..UsrName) then return "nsUsr" end
  347.  local file = fs.open(UsrDir.."/"..UsrName)
  348.  local opass = file.readLine()
  349.  file.close()
  350.  if opass == hash.sha256(UsrPass) then
  351.   fs.delete(UsrDir.."/"..UsrName)
  352.   return true
  353.  else
  354.   return "pww"
  355.  end
  356. end
  357.  
  358.  
  359.  -- runs the Server Shell (should only be used in parralel with runServer) (currently broken; using code for example program)
  360. local function runServerShell()
  361.  local ServCol
  362.  if term.isColor() then ServCol = {colors.yellow, colors.lightBlue} else ServCol = {colors.lightGray, colors.white} end
  363.  local function clearShellScreen()
  364.   term.setBackgroundColor(colors.black)
  365.   term.clear()
  366.   term.setCursorPos(1,1)
  367.   term.setTextColor(ServCol[1])
  368.   print("ccFTP Server Shell")
  369.  end
  370.  clearShellScreen()
  371.  while(true) do
  372.   local opull = os.pullEvent
  373.   term.setTextColor(ServCol[2])
  374.   write("-> ")
  375.   term.setTextColor(colors.white)
  376.   os.pullEvent = os.pullEventRaw
  377.   local input = string.lower(read())
  378.   os.pullEvent = opull
  379.   if input == "reboot" then
  380.    os.reboot()
  381.   elseif input == "shutdown" then
  382.    os.shutdown()
  383.   elseif input == "close" then
  384.    rednet.unhost("ccFTP", runningHost)
  385.    break
  386.   elseif input == "clear" then
  387.    clearShellScreen()
  388.   elseif input == "change hostname" then
  389.    if runningHost ~= nil then
  390.     os.pullEvent = os.pullEventRaw
  391.     term.setTextColor(ServCol[2])
  392.     print("Current Hostname: "..runningHost)
  393.     write("New Hostname: ")
  394.     term.setTextColor(colors.white)
  395.     local input = read()
  396.     os.pullEvent = opull
  397.     if input ~= nil then
  398.      rednet.unhost("ccFTP", runningHost)
  399.      rednet.host("ccFTP", input)
  400.      runningHost = input
  401.     else
  402.      printError("Please enter a Hostname!")
  403.     end
  404.    else
  405.     print("There is no ccFTP Server running on this computer!")
  406.    end
  407.    os.pullEvent = opull
  408.   elseif input == "create User" then
  409.    os.pullEvent = os.pullEventRaw
  410.    term.setTextColor(ServCol[2])
  411.    print("User to create: ")
  412.    term.setTextColor(colors.white)
  413.    local user = read()
  414.    if user ~= "" then
  415.     term.setTextColor(ServCol[2])
  416.     print("Password: ")
  417.     term.setTextColor(colors.white)
  418.     local pass = read("*")
  419.     if pass ~= "" then
  420.      local res = createUser(user, pass)
  421.      if res == true then
  422.       term.setTextColor(ServCol[1])
  423.       print("User created!")
  424.      elseif res == "UsrE" then
  425.       printError("User already exists!")
  426.      end
  427.     else
  428.      printError("Please specify a Password!")
  429.     end
  430.    else
  431.     printError("Please specify a Username!")
  432.    end
  433.    os.pullEvent = opull
  434.   elseif input == "change Username" then
  435.    os.pullEvent = os.pullEventRaw
  436.    term.setTextColor(ServCol[2])
  437.    write("Current Username: ")
  438.    term.setTextColor(colors.white)
  439.    local oName = read()
  440.    if oName ~= "" then
  441.     term.setTextColor(ServCol[2])
  442.     write("Current Password: ")
  443.     term.setTextColor(colors.white)
  444.     local pass = read("*")
  445.     if pass ~= "" then
  446.      term.setTextColor(ServCol[2])
  447.      write("New Username: ")
  448.      term.setTextColor(colors.white)
  449.      local nName = read()
  450.      if nName ~= "" then
  451.       renameUser(oName, nName, pass)
  452.       if res == true then
  453.        term.setTextColor(ServCol[1])
  454.        print("Renamed "..oName.." to "..nName)
  455.       elseif res == "nsUsr" then
  456.        printError("User doesn not exist!")
  457.       elseif res == "nUsrE" then
  458.        printError("New Username is already occupied!")
  459.       elseif res == "pww" then
  460.        printError("Password wrong!")
  461.       end
  462.      else
  463.       printError("Please enter in the new Username!")
  464.      end
  465.     else
  466.      printError("Please enter in the current Password!")
  467.     end
  468.    else
  469.     printError("Please put in the current Username!")
  470.    end
  471.    os.pullEvent = opull
  472.   elseif input == "change Password" then
  473.    os.pullEvent = os.pullEventRaw
  474.    term.setTextColor(ServCol[2])
  475.    write("Username: ")
  476.    term.setTextColor(colors.white)
  477.    local Uname = read()
  478.    if Uname ~= "" then
  479.     term.setTextColor(ServCol[2])
  480.     write("Current Password: ")
  481.     term.setTextColor(colors.white)
  482.     local opass = read("*")
  483.     if opass ~= "" then
  484.      term.setTextColor(ServCol[2])
  485.      write("New Password: ")
  486.      term.setTextColor(colors.white)
  487.      local npass = read()
  488.      if nName ~= "" then
  489.       local res = changeUserPass(Uname, opass, npass)
  490.       if res == true then
  491.        term.setTextColor(ServCol[1])
  492.        print("Changed Password from "..Uname)
  493.       elseif res == "nsUsr" then
  494.        printError("User does not exist!")
  495.       elseif res == "pww" then
  496.        printError("Password wrong!")
  497.       end
  498.      else
  499.       printError("Please enter in the new Username!")
  500.      end
  501.     else
  502.      printError("Please enter in the current Password!")
  503.     end
  504.    else
  505.     printError("Please put in the current Username!")
  506.    end
  507.    os.pullEvent = opull
  508.   elseif input == "delete User" then
  509.    os.pullEvent = os.pullEventRaw
  510.    term.setTextColor(ServCol[2])
  511.    write("Username: ")
  512.    term.setTextColor(colors.white)
  513.    local Uname = read()
  514.    if Uname ~= "" then
  515.     term.setTextColor(ServCol[2])
  516.     write("Password: ")
  517.     term.setTextColor(colors.white)
  518.     local pass = read("*")
  519.     if pass ~= "" then
  520.      local res = removeUser(Uname, pass)
  521.      if res == true then
  522.       term.setTextColor(ServCol[1])
  523.       print("Deleted User "..Uname)
  524.      elseif res == "nsUsr" then
  525.       printError("User does not exists!")
  526.      elseif res == "pww" then
  527.       printError("Password wrong!")
  528.      end
  529.     else
  530.      printError("Please enter in a password!")
  531.     end
  532.    else
  533.     printError("Please specify the Username!")
  534.    end
  535.    os.pullEvent = opull
  536.   end
  537.  end
  538. end
  539.  
  540.  
  541.  -- gets the Directory Tree for the specified Subdirectory (optional)
  542. function getDirCont(Hostname, UsrName, UsrPass, Subdir)
  543.  if Hostname == nil then
  544.   error("Hostname required!")
  545.  elseif UsrName == nil then
  546.   error("Username required!")
  547.  elseif UsrPass == nil then
  548.   error("Password required!")
  549.  end
  550.  Subdir = Subdir or ""
  551.  checkAPI()
  552.  if checkModem() then
  553.   local key, iv = unfoldkeyC(UsrPass)
  554.   local hosterID = sendMessageC(Hostname, UsrName, hash.sha256("iv"..iv[15]), {"DirCont", Subdir})
  555.   if hosterID then
  556.    local response, senderID = waitForMessage()
  557.    if senderID == hosterID then
  558.     if response[2] ~= nil then
  559.      return response[1], response[2]
  560.     else
  561.      return response
  562.     end
  563.    end
  564.   else
  565.   end
  566.  else
  567.   error("No Modem attached!")
  568.  end
  569. end
  570.  
  571.  -- gets a single File from FTP-Server (FileHost is the full path to the file on the hoster ; FileClient sets the path where the file should be saved)
  572. function getFile(Hostname, UsrName, UsrPass, FileHost, FileClient)
  573.  if Hostname == nil then
  574.   error("Hostname required!")
  575.  elseif UsrName == nil then
  576.   error("Username required!")
  577.  elseif UsrPass == nil then
  578.   error("Password required!")
  579.  elseif FileHost == nil then
  580.   error("File must be specified!")
  581.  elseif FileClient == nil then
  582.   error("File must be specified!")
  583.  end
  584.  checkAPI()
  585.  if checkModem() then
  586.   local key, iv = unfoldkeyC(UsrPass)
  587.   local hosterID = sendMessageC(Hostname, UsrName, hash.sha256("iv"..iv[15]), {"getFile", FileHost})
  588.   if hosterID then
  589.    while(true) do
  590.     local response, senderID = waitForMessage()
  591.     if senderID == hosterID then
  592.      if response[1] == hash.sha256("iv"..iv[16]) then
  593.       local content = ccaes.decrypt_bytestream(response[2], key, iv)
  594.       local file = fs.open(FileClient, "wb")
  595.       for i = 1, #content do
  596.        file.write(content[i])
  597.       end
  598.       file.close()
  599.       return true
  600.      else
  601.       return response
  602.      end
  603.     end
  604.    end
  605.   end
  606.  else
  607.   error("No Modem attached!")
  608.  end
  609. end
  610.  
  611.  -- puts a single file onto the FTP-Server (FileClient is the path of the file which should be uploaded ; FileHost sets the full path, where the file should be saved)
  612. function pushFile(Hostname, UsrName, UsrPass, FileClient, FileHost)
  613.  if Hostname == nil then
  614.   error("Hostname required!")
  615.  elseif UsrName == nil then
  616.   error("Username required!")
  617.  elseif UsrPass == nil then
  618.   error("Password required!")
  619.  elseif FileHost == nil then
  620.   error("File must be specified!")
  621.  elseif FileClient == nil then
  622.   error("File must be specified!")
  623.  elseif not fs.exists(FileClient) then
  624.   error("File must exists!")
  625.  end
  626.  checkAPI()
  627.  if checkModem() then
  628.   local key, iv = unfoldkeyC(UsrPass)
  629.   local file = fs.open(FileClient, "rb")
  630.   local fileData = {}
  631.   local fileByte = file.read()
  632.   repeat
  633.   table.insert(fileData, fileByte)
  634.   fileByte = file.read()
  635.   until fileByte == nil
  636.   file.close()
  637.   fileData = ccaes.encrypt_bytestream(fileData, key, iv)
  638.   local hosterID = sendMessageC(Hostname, UsrName, hash.sha256("iv"..iv[15]), {"pushFile", FileHost, fileData})
  639.   if hosterID then
  640.    while(true) do
  641.     local response, senderID = waitForMessage()
  642.     if senderID == hosterID then
  643.      if response == "OK" then
  644.       return true
  645.      else
  646.       return commandtab
  647.      end
  648.     end
  649.    end
  650.   end
  651.  else
  652.   error("No Modem attached!")
  653.  end
  654. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement