Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- MIT License
- Copyright © 2016 Chickenbreadlp
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- ]]
- local ccFTPRev = "Rev2"
- local runningFTPHost = nil
- -- GitHub File Downloader for Self-Suppling
- local function GITget(branch, file)
- local response = http.get(
- "https://raw.githubusercontent.com/Chickenbreadlp/ReboOSt/"..branch.."/"..textutils.urlEncode( file )
- )
- if response then
- local sResponse = response.readAll()
- response.close()
- return sResponse
- else
- end
- end
- local function GITdownload(branch, filename, sFile)
- if fs.exists( sFile ) then
- return
- end
- local res = GITget(branch, filename)
- if res then
- local file = fs.open( sFile, "w" )
- file.write( res )
- file.close()
- end
- end
- -- Pastebin Downloader for Self-Suppling
- local function PASget(paste)
- local response = http.get(
- "http://pastebin.com/raw/"..textutils.urlEncode( paste )
- )
- if response then
- local sResponse = response.readAll()
- response.close()
- return sResponse
- else
- end
- end
- local function PASdownload(paste, sFile)
- if fs.exists( sFile ) then
- return
- end
- local res = PASget(paste)
- if res then
- local file = fs.open( sFile, "w" )
- file.write( res )
- file.close()
- end
- end
- -- Way to create a keypair for AES from single case-sensitive key for Server functions
- local function unfoldkeyS(keyhash)
- math.randomseed(tonumber(keyhash, 36))
- local key = {}
- local iv = {}
- for i=1, 16 do
- key[i] = math.random(0, 0xFF)
- iv[i] = math.random(0, 0xFF)
- end
- math.randomseed(os.clock())
- return key, iv
- end
- -- Way to create a keypair for AES from single case-sensitive key for Clint functions
- local function unfoldkeyC(Key)
- local keyhash = hash.sha256(Key)
- math.randomseed(tonumber(keyhash, 36))
- local key = {}
- local iv = {}
- for i=1, 16 do
- key[i] = math.random(0, 0xFF)
- iv[i] = math.random(0, 0xFF)
- end
- math.randomseed(os.clock())
- return key, iv
- end
- -- checks if needed APIs are available and (if not) do exist
- local function checkAPI()
- if ccaes == nil then
- if fs.exists("/.ccftp/ccaes") then
- os.loadAPI("/.ccftp/ccaes")
- else
- PASdownload("rCYDnCxn", "/.ccftp/ccaes")
- os.loadAPI("/.ccftp/ccaes")
- end
- end
- if hash == nil then
- if fs.exists("/.ccftp/hash") then
- os.loadAPI("/.ccftp/hash")
- else
- GITdownload("release", "ReboOSt/APIs/encryption", "/.ccftp/hash")
- os.loadAPI("/.ccftp/hash")
- end
- end
- end
- -- checks for a Modem
- local function checkModem()
- if rednet.isOpen() then
- return true
- end
- for _, side in ipairs( rs.getSides() ) do
- if peripheral.isPresent( side ) and peripheral.getType( side ) == "modem" then
- rednet.open( side )
- return true
- end
- end
- return false
- end
- -- waits for receiving a message and unserialize it
- local function waitForMessage(typ)
- local senderID = nil
- local command = nil
- if typ == "C" then
- senderID, command = rednet.receive("ccFTP", 5)
- elseif typ == "S" then
- senderID, command = rednet.receive("ccFTP")
- end
- -- command = textutils.unserialize(command)
- return command, senderID
- end
- -- sendMessage function for Client tools
- local function sendMessageC(Hostname, UsrName, PassIV, command)
- local command = { UsrName, PassIV, command }
- -- textutils.serialize(command)
- local hostID = rednet.lookup("ccFTP", Hostname)
- if hostID == nil then
- return nil
- else
- rednet.send(hostID, command, "ccFTP")
- return hostID
- end
- end
- -- sendMessage function for Server tools
- local function sendMessageS(response, ID)
- -- command = textutils.serialize(command)
- rednet.send(ID, response, "ccFTP")
- end
- -- returns the local API Rev
- function getClientVer()
- return ccFTPRev
- end
- -- returns the API Rev of Hostname or "nsh" if Hostname was not found
- function getServerVer(Hostname)
- checkAPI()
- if checkModem() then
- local hosterID = sendMessageC(Hostname, "VerCheck", hash.sha256("VerCheck"), "VerCheck")
- if hosterID then
- local response, senderID = waitForMessage("C")
- if senderID == hosterID then
- return response
- elseif senderID == nil then
- return "nsh"
- end
- elseif hosterID == nil then
- return "nsh"
- end
- end
- end
- ---- Server Functions ----
- -- returns true and current hostname if hostname is still active else it returns false
- function getRunningHost()
- if runningFTPHost ~= nil then
- return true, runningFTPHost
- else
- return false
- end
- end
- -- returns true if hostname was still active and is now shutdown, false if no hostname was running
- function closeServer()
- if runningFTPHost ~= nil then
- rednet.unhost("ccFTP", runningFTPHost)
- runningFTPHost = nil
- return true
- else
- return false
- end
- end
- -- 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)
- -- It is not recommended to use Root Directory as FTP Share
- function runServer(Hostname, loopoff, FtpDir, UsrDir)
- if Hostname == nil then
- error("Hostname missing!")
- end
- local UsrDir = UsrDir
- local FtpDir = FtpDir
- local loopoff = loopoff
- if type(loopoff) ~= "boolean" and type(loopoff) ~= "nil" then
- loopoff = false
- end
- if UsrDir == nil then UsrDir = "/.ccftp/Users" end
- if FtpDir == nil then FtpDir = "/FTP_Share" end
- if not fs.exists(FtpDir) then fs.makeDir(FtpDir) end
- checkAPI()
- if checkModem() then
- if runningFTPHost ~= Hostname and runningFTPHost ~= nil then
- closeServer()
- end
- rednet.host("ccFTP", Hostname)
- runningFTPHost = Hostname
- while true do
- local commandtab = nil
- local sender = nil
- commandtab, sender = waitForMessage("S")
- if #commandtab >= 3 then
- if commandtab[1] == "VerCheck" and commandtab[2] == hash.sha256("VerCheck") and commandtab[3] == "VerCheck" then
- sendMessageS(ccFTPRev, sender)
- if loopoff == true then
- return true, sender, "VerCheck", ""
- end
- elseif fs.exists(UsrDir.."/"..commandtab[1]) then
- local file = fs.open(UsrDir.."/"..commandtab[1], "r")
- local pass = file.readLine()
- file.close()
- local key, iv = unfoldkeyS(pass)
- if hash.sha256("iv"..iv[15]) == commandtab[2] then
- if commandtab[3][1] == "DirCont" then
- if #commandtab[3] >= 2 then
- if fs.exists(FtpDir.."/"..commandtab[3][2]) and fs.isDir(FtpDir.."/"..commandtab[3][2]) then
- local DirCont = fs.list(FtpDir.."/"..commandtab[3][2])
- local DirIdx = {}
- for _, content in ipairs(DirCont) do
- if fs.isDir(FtpDir.."/"..content) then
- table.insert(DirIdx, content)
- end
- end
- sendMessageS( { DirCont, DirIdx } , sender)
- if loopoff == true then
- return true, sender, "DirCont", commandtab[3][2]
- end
- else
- sendMessageS("ddne", sender)
- if loopoff == true then
- return false, sender, "DirCont", "ddne"
- end
- end
- else
- sendMessageS("nea", sender)
- if loopoff == true then
- return false, sender, "DirCont", "nea"
- end
- end
- elseif commandtab[3][1] == "getFile" then
- if #commandtab[3] >= 2 then
- if fs.exists(FtpDir.."/"..commandtab[3][2]) and not fs.isDir(FtpDir.."/"..commandtab[3][2]) then
- local file = fs.open(FtpDir.."/"..commandtab[3][2], "rb")
- local fileData = {}
- local filebyte = file.read()
- repeat
- table.insert(fileData, filebyte)
- filebyte =file.read()
- until filebyte == nil
- file.close()
- fileData = ccaes.encrypt_bytestream(fileData, key, iv)
- local response = { hash.sha256("iv"..iv[16]), fileData }
- sendMessageS(response, sender)
- if loopoff == true then
- return true, sender, "getFile", commandtab[3][2]
- end
- else
- sendMessageS("fdne", sender)
- if loopoff == true then
- return false, sender, "getFile", "fdne"
- end
- end
- else
- sendMessageS("nea", sender)
- if loopoff == true then
- return false, sender, "getFile", "nea"
- end
- end
- elseif commandtab[3][1] == "pushFile" then
- if #commandtab[3] >= 3 then
- local decdat = ccaes.decrypt_bytestream(commandtab[3][3], key, iv)
- local file = fs.open(FtpDir.."/"..commandtab[3][2], "wb")
- for i = 1, #decdat do
- file.write(decdat[i])
- end
- file.close()
- sendMessageS("OK", sender)
- if loopoff == true then
- return true, sender, "pushFile", commandtab[3][2]
- end
- else
- sendMessageS("nea", sender)
- if loopoff == true then
- return false, sender, "pushFile", "nea"
- end
- end
- elseif commandtab[3][1] == "delFile" then
- if #commandtab[3] >= 2 then
- if fs.exists(FtpDir.."/"..commandtab[3][2]) then
- fs.delete(FtpDir.."/"..commandtab[3][2])
- sendMessageS("OK", sender)
- if loopoff == true then
- return true, sender, "delFile", commandtab[3][2]
- end
- else
- sendMessageS("fdne", sender)
- if loopoff == true then
- return false, sender, "delFile", "fdne"
- end
- end
- else
- sendMessageS("nea", sender)
- if loopoff == true then
- return false, sender, "delFile", "nea"
- end
- end
- else
- sendMessageS("nsc", sender)
- if loopoff == true then
- return false, sender, commandtab[3][1], "nsc"
- end
- end
- else
- sendMessageS("pww", sender)
- if loopoff == true then
- return false, sender, commandtab[3][1], "pww"
- end
- end
- else
- sendMessageS("nsu", sender)
- if loopoff == true then
- return false, sender, commandtab[3][1], "nsu"
- end
- end
- else
- sendMessageS("nea", sender)
- if loopoff == true then
- return false, sender, "nea"
- end
- end
- end
- else
- return "nMa"
- end
- end
- -- 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
- function createUser(UsrName, UsrPass, UsrDir)
- checkAPI()
- if UsrName == nil then return "nUsrN" end
- if UsrPass == nil then return "nUsrP" end
- local UsrDir = UsrDir or "/.ccftp/Users"
- if fs.exists(UsrDir.."/"..UsrName) or UsrName == "VerCheck" then return "UsrE" end
- local file = fs.open(UsrDir.."/"..UsrName, "w")
- file.writeLine(hash.sha256(UsrPass))
- file.close()
- return true
- end
- -- 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
- function renameUser(oUsrName, nUsrName, UsrPass, UsrDir)
- checkAPI()
- if oUsrName == nil then return "noUsrN" end
- if nUsrName == nil then return "nnUsrN" end
- if UsrPass == nil then return "nUsrP" end
- local UsrDir = UsrDir or "/.ccftp/Users"
- if not fs.exists(UsrDir.."/"..oUsrName) then return "nsUsr" end
- if fs.exists(UsrDir.."/"..nUsrName) or nUsrName == "VerCheck" then return "nUsrE" end
- local file = fs.open(UserDir.."/"..oUsrName, "r")
- local opass = file.readLine()
- file.close()
- if opass == hash.sha256(UsrPass) then
- fs.move(UsrDir.."/"..oUsrName, UsrDir.."/"..nUsrName)
- return true
- else
- return "pww"
- end
- end
- -- 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
- function changeUserPass(UsrName, oUsrPass, nUsrPass, UsrDir)
- checkAPI()
- if UsrName == nil then return "nUsrN" end
- if oUsrPass == nil then return "noUsrP" end
- if nUsrPass == nil then return "nnUsrP" end
- local UsrDir = UsrDir or "/.ccftp/Users"
- if not fs.exists(UsrDir.."/"..UsrName) then return "nsUsr" end
- local file = fs.open(UsrDir.."/"..UsrName, "r")
- local opass = file.readLine()
- file.close()
- if opass == hash.sha256(oUsrPass) then
- local file = fs.open(UsrDir.."/"..UsrName, "w")
- file.writeLine(hash.sha256(nUsrPass))
- file.close()
- return true
- else
- return "pww"
- end
- end
- -- 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
- function removeUser(UsrName, UsrPass, UsrDir)
- checkAPI()
- if UsrName == nil then return "nUsrN" end
- if UsrPass == nil then return "nUsrP" end
- local UsrDir = UsrDir or "/.ccftp/Users"
- if not fs.exists(UsrDir.."/"..UsrName) then return "nsUsr" end
- local file = fs.open(UsrDir.."/"..UsrName)
- local opass = file.readLine()
- file.close()
- if opass == hash.sha256(UsrPass) then
- fs.delete(UsrDir.."/"..UsrName)
- return true
- else
- return "pww"
- end
- end
- -- runs the Server Shell (should only be used in parralel with runServer) (currently broken; using code for example program)
- local function runServerShell()
- local ServCol
- if term.isColor() then ServCol = {colors.yellow, colors.lightBlue} else ServCol = {colors.lightGray, colors.white} end
- local function clearShellScreen()
- term.setBackgroundColor(colors.black)
- term.clear()
- term.setCursorPos(1,1)
- term.setTextColor(ServCol[1])
- print("ccFTP Server Shell")
- end
- clearShellScreen()
- while(true) do
- local opull = os.pullEvent
- term.setTextColor(ServCol[2])
- write("-> ")
- term.setTextColor(colors.white)
- os.pullEvent = os.pullEventRaw
- local input = string.lower(read())
- os.pullEvent = opull
- if input == "reboot" then
- os.reboot()
- elseif input == "shutdown" then
- os.shutdown()
- elseif input == "close" then
- rednet.unhost("ccFTP", runningHost)
- break
- elseif input == "clear" then
- clearShellScreen()
- elseif input == "change hostname" then
- if runningHost ~= nil then
- os.pullEvent = os.pullEventRaw
- term.setTextColor(ServCol[2])
- print("Current Hostname: "..runningHost)
- write("New Hostname: ")
- term.setTextColor(colors.white)
- local input = read()
- os.pullEvent = opull
- if input ~= nil then
- rednet.unhost("ccFTP", runningHost)
- rednet.host("ccFTP", input)
- runningHost = input
- else
- printError("Please enter a Hostname!")
- end
- else
- print("There is no ccFTP Server running on this computer!")
- end
- os.pullEvent = opull
- elseif input == "create User" then
- os.pullEvent = os.pullEventRaw
- term.setTextColor(ServCol[2])
- print("User to create: ")
- term.setTextColor(colors.white)
- local user = read()
- if user ~= "" then
- term.setTextColor(ServCol[2])
- print("Password: ")
- term.setTextColor(colors.white)
- local pass = read("*")
- if pass ~= "" then
- local res = createUser(user, pass)
- if res == true then
- term.setTextColor(ServCol[1])
- print("User created!")
- elseif res == "UsrE" then
- printError("User already exists!")
- end
- else
- printError("Please specify a Password!")
- end
- else
- printError("Please specify a Username!")
- end
- os.pullEvent = opull
- elseif input == "change Username" then
- os.pullEvent = os.pullEventRaw
- term.setTextColor(ServCol[2])
- write("Current Username: ")
- term.setTextColor(colors.white)
- local oName = read()
- if oName ~= "" then
- term.setTextColor(ServCol[2])
- write("Current Password: ")
- term.setTextColor(colors.white)
- local pass = read("*")
- if pass ~= "" then
- term.setTextColor(ServCol[2])
- write("New Username: ")
- term.setTextColor(colors.white)
- local nName = read()
- if nName ~= "" then
- renameUser(oName, nName, pass)
- if res == true then
- term.setTextColor(ServCol[1])
- print("Renamed "..oName.." to "..nName)
- elseif res == "nsUsr" then
- printError("User doesn not exist!")
- elseif res == "nUsrE" then
- printError("New Username is already occupied!")
- elseif res == "pww" then
- printError("Password wrong!")
- end
- else
- printError("Please enter in the new Username!")
- end
- else
- printError("Please enter in the current Password!")
- end
- else
- printError("Please put in the current Username!")
- end
- os.pullEvent = opull
- elseif input == "change Password" then
- os.pullEvent = os.pullEventRaw
- term.setTextColor(ServCol[2])
- write("Username: ")
- term.setTextColor(colors.white)
- local Uname = read()
- if Uname ~= "" then
- term.setTextColor(ServCol[2])
- write("Current Password: ")
- term.setTextColor(colors.white)
- local opass = read("*")
- if opass ~= "" then
- term.setTextColor(ServCol[2])
- write("New Password: ")
- term.setTextColor(colors.white)
- local npass = read()
- if nName ~= "" then
- local res = changeUserPass(Uname, opass, npass)
- if res == true then
- term.setTextColor(ServCol[1])
- print("Changed Password from "..Uname)
- elseif res == "nsUsr" then
- printError("User does not exist!")
- elseif res == "pww" then
- printError("Password wrong!")
- end
- else
- printError("Please enter in the new Username!")
- end
- else
- printError("Please enter in the current Password!")
- end
- else
- printError("Please put in the current Username!")
- end
- os.pullEvent = opull
- elseif input == "delete User" then
- os.pullEvent = os.pullEventRaw
- term.setTextColor(ServCol[2])
- write("Username: ")
- term.setTextColor(colors.white)
- local Uname = read()
- if Uname ~= "" then
- term.setTextColor(ServCol[2])
- write("Password: ")
- term.setTextColor(colors.white)
- local pass = read("*")
- if pass ~= "" then
- local res = removeUser(Uname, pass)
- if res == true then
- term.setTextColor(ServCol[1])
- print("Deleted User "..Uname)
- elseif res == "nsUsr" then
- printError("User does not exists!")
- elseif res == "pww" then
- printError("Password wrong!")
- end
- else
- printError("Please enter in a password!")
- end
- else
- printError("Please specify the Username!")
- end
- os.pullEvent = opull
- end
- end
- end
- ---- Client Functions ----
- -- gets the Directory Tree for the specified Subdirectory (optional)
- function getDirCont(Hostname, UsrName, UsrPass, Subdir)
- if Hostname == nil then
- return "nHn"
- elseif UsrName == nil then
- return "nUsrN"
- elseif UsrPass == nil then
- return "nUsrP"
- end
- Subdir = Subdir or ""
- checkAPI()
- if checkModem() then
- local key, iv = unfoldkeyC(UsrPass)
- local hosterID = sendMessageC(Hostname, UsrName, hash.sha256("iv"..iv[15]), {"DirCont", Subdir})
- if hosterID then
- local response, senderID = waitForMessage("C")
- if senderID == hosterID then
- if response[2] ~= nil then
- return response[1], response[2]
- else
- return response
- end
- elseif senderID == nil then
- return "nsh"
- end
- elseif hosterID == nil then
- return "nsh"
- end
- else
- return "nMa"
- end
- end
- -- gets a single File from FTP-Server (FileHost is the full path to the file in the Share ; FileClient sets the path where the file should be saved)
- function getFile(Hostname, UsrName, UsrPass, FileHost, FileClient)
- if Hostname == nil then
- return "nHn"
- elseif UsrName == nil then
- return "nUsrN"
- elseif UsrPass == nil then
- return "nUsrP"
- elseif FileHost == nil then
- return "nFPH"
- elseif FileClient == nil then
- return "nFPC"
- end
- checkAPI()
- if checkModem() then
- local key, iv = unfoldkeyC(UsrPass)
- local hosterID = sendMessageC(Hostname, UsrName, hash.sha256("iv"..iv[15]), {"getFile", FileHost})
- if hosterID then
- local response, senderID = waitForMessage("C")
- if senderID == hosterID then
- if response[1] == hash.sha256("iv"..iv[16]) then
- local content = ccaes.decrypt_bytestream(response[2], key, iv)
- local file = fs.open(FileClient, "wb")
- for i = 1, #content do
- file.write(content[i])
- end
- file.close()
- return true
- else
- return response
- end
- elseif senderID == nil then
- return "nsh"
- end
- else
- return "nsh"
- end
- else
- return "nMa"
- end
- end
- -- 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)
- function pushFile(Hostname, UsrName, UsrPass, FileClient, FileHost)
- if Hostname == nil then
- return "nHn"
- elseif UsrName == nil then
- return "nUsrN"
- elseif UsrPass == nil then
- return "nUsrP"
- elseif FileHost == nil then
- return "nFPH"
- elseif FileClient == nil then
- return "nFPC"
- elseif not fs.exists(FileClient) then
- return "FPCnE"
- end
- checkAPI()
- if checkModem() then
- local key, iv = unfoldkeyC(UsrPass)
- local file = fs.open(FileClient, "rb")
- local fileData = {}
- local fileByte = file.read()
- repeat
- table.insert(fileData, fileByte)
- fileByte = file.read()
- until fileByte == nil
- file.close()
- fileData = ccaes.encrypt_bytestream(fileData, key, iv)
- local hosterID = sendMessageC(Hostname, UsrName, hash.sha256("iv"..iv[15]), {"pushFile", FileHost, fileData})
- if hosterID then
- local response, senderID = waitForMessage("C")
- if senderID == hosterID then
- if response == "OK" then
- return true
- else
- return response
- end
- elseif senderID == nil then
- return "nsh"
- end
- else
- return "nsh"
- end
- else
- return "nMa"
- end
- end
- -- removes a single File from the FTP-Server
- function removeFile(Hostname, UsrName, UsrPass, FileHost)
- if Hostname == nil then
- return "nHn"
- elseif UsrName == nil then
- return "nUsrN"
- elseif UsrPass == nil then
- return "nUsrP"
- elseif FileHost == nil then
- return "nFPH"
- end
- checkAPI()
- if checkModem() then
- local key, iv = unfoldkeyC(UsrPass)
- local hosterID = sendMessageC(Hostname, UsrName, hash.sha256("iv"..iv[15]), {"delFile", FileHost})
- if hosterID then
- local response, senderID = waitForMessage("C")
- if senderID == hosterID then
- if response == "OK" then
- return true
- else
- return response
- end
- elseif senderID == nil then
- return "nsh"
- end
- elseif hosterID == nil then
- return "nsh"
- end
- else
- return "nMa"
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement