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 = "Rev3"
- 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 AES256 from SHA256 keyhash
- local function unfoldkeyS(keyhash)
- math.randomseed(tonumber(keyhash, 36))
- local key = {}
- local iv = {}
- for i=1, 32 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 AES256 from single case-sensitive key
- local function unfoldkeyC(Key)
- local keyhash = hash.sha256(Key)
- math.randomseed(tonumber(keyhash, 36))
- local key = {}
- local iv = {}
- for i=1, 32 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, ClientVer, command)
- local command = { UsrName, PassIV, command, ClientVer }
- -- 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, hash.sha256("VerCheck"), hash.sha256("VerCheck"), ccFTPRev, "VerCheck")
- if hosterID then
- local response, senderID = waitForMessage("C")
- if senderID == hosterID and response ~= "nsu" then
- return response
- elseif response == "nsu" then
- return "Rev2"
- 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
- return "nHn"
- end
- local UsrDir = UsrDir
- local FtpDir = FtpDir
- local loopoff = loopoff
- if type(loopoff) ~= "boolean" then
- loopoff = false
- end
- if type(UsrDir) ~= "string" then UsrDir = "/.ccftp/Users" end
- if type(FtpDir) ~= "string" 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 type(commandtab) == "table" then
- if #commandtab >= 3 then
- if (commandtab[1] == hash.sha256("VerCheck") or commandtab[1] == "VerCheck") and commandtab[2] == hash.sha256("VerCheck") and commandtab[3] == "VerCheck" then
- sendMessageS(ccFTPRev, sender)
- if loopoff == true and commandtab[1] == "VerCheck" then
- return true, sender, "VerCheck", "", ""
- end
- elseif fs.exists(UsrDir.."/"..commandtab[1]) and type(commandtab[3]) == "string" and commandtab[4] == ccFTPRev 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
- local decrypttab = textutils.unserialize(ccaes.decrypt_str(commandtab[3], key, iv))
- if type(decrypttab) == "table" then
- if decrypttab[1] == "DirCont" then
- if #decrypttab >= 2 then
- if fs.exists(FtpDir.."/"..decrypttab[2]) and fs.isDir(FtpDir.."/"..decrypttab[2]) then
- local DirConto = fs.list(FtpDir.."/"..decrypttab[2])
- local DirCont = {}
- local DirIdx = {}
- for _, content in ipairs(DirConto) do
- if fs.isDir(FtpDir.."/"..content) then
- table.insert(DirIdx, content)
- else
- table.insert(DirCont, content)
- end
- end
- local resa = ccaes.encrypt_str(textutils.serialize(DirCont), key, iv)
- local resb = ccaes.encrypt_str(textutils.serialize(DirIdx), key, iv)
- sendMessageS({true, resa, resb}, sender)
- if loopoff == true then
- return true, sender, commandtab[1], "DirCont", decrypttab[2]
- end
- else
- sendMessageS({true, ccaes.encrypt_str("ddne", key, iv)}, sender)
- if loopoff == true then
- return false, sender, commandtab[1], "DirCont", "ddne"
- end
- end
- else
- sendMessageS({true, ccaes.encrypt_str("nea", key, iv)}, sender)
- if loopoff == true then
- return false, sender, commandtab[1], "DirCont", "nea"
- end
- end
- elseif decrypttab[1] == "getFile" then
- if #decrypttab >= 2 then
- if fs.exists(FtpDir.."/"..decrypttab[2]) and not fs.isDir(FtpDir.."/"..decrypttab[2]) then
- local file = fs.open(FtpDir.."/"..decrypttab[2], "rb")
- local fileData = {}
- local filebyte = file.read()
- repeat
- table.insert(fileData, filebyte)
- filebyte = file.read()
- until filebyte == nil
- file.close()
- local response = ccaes.encrypt_bytestream(fileData, key, iv)
- response = { hash.sha256("iv"..iv[16]), response }
- sendMessageS(response, sender)
- if loopoff == true then
- return true, sender, commandtab[1], "getFile", decrypttab[2]
- end
- else
- sendMessageS({true, ccaes.encrypt_str("fdne", key, iv)}, sender)
- if loopoff == true then
- return false, sender, commandtab[1], "getFile", "fdne"
- end
- end
- else
- sendMessageS({true, ccaes.encrypt_str("nea", key, iv)}, sender)
- if loopoff == true then
- return false, sender, commandtab[1], "getFile", "nea"
- end
- end
- elseif decrypttab[1] == "pushFile" then
- if #decrypttab >= 3 then
- local decdat = ccaes.decrypt_bytestream(decrypttab[3], key, iv)
- local file = fs.open(FtpDir.."/"..decrypttab[2], "wb")
- for i = 1, #decdat do
- file.write(decdat[i])
- end
- file.close()
- sendMessageS({true, ccaes.encrypt_str("OK", key, iv)}, sender)
- if loopoff == true then
- return true, sender, commandtab[1], "pushFile", decrypttab[2]
- end
- else
- sendMessageS({true, ccaes.encrypt_str("nea", key, iv)}, sender)
- if loopoff == true then
- return false, sender, commandtab[1], "pushFile", "nea"
- end
- end
- elseif decrypttab[1] == "delFile" then
- if #decrypttab >= 2 then
- if fs.exists(FtpDir.."/"..decrypttab[2]) then
- fs.delete(FtpDir.."/"..decrypttab[2])
- sendMessageS({true, ccaes.encrypt_str("OK", key, iv)}, sender)
- if loopoff == true then
- return true, sender, commandtab[1], "delFile", decrypttab[2]
- end
- else
- sendMessageS({true, ccaes.encrypt_str("fdne", key, iv)}, sender)
- if loopoff == true then
- return false, sender, commandtab[1], "delFile", "fdne"
- end
- end
- else
- sendMessageS({true, ccaes.encrypt_str("nea", key, iv)}, sender)
- if loopoff == true then
- return false, sender, commandtab[1], "delFile", "nea"
- end
- end
- else
- sendMessageS({true, ccaes.encrypt_str("nsc", key, iv)}, sender)
- if loopoff == true then
- return false, sender, commandtab[1], decrypttab[1], "nsc"
- end
- end
- end
- else
- sendMessageS({false, "pww"}, sender)
- if loopoff == true then
- return false, sender, commandtab[1], "", "pww"
- end
- end
- elseif commandtab[4] ~= ccFTPRev then
- sendMessageS({false, "wCV"}, sender)
- if loopoff == true then
- return false, sender, commandtab[1], "", "wCV"
- end
- else
- sendMessageS({false, "nsu"}, sender)
- if loopoff == true then
- return false, sender, commandtab[1], "", "nsu"
- end
- end
- else
- sendMessageS({false, "nea"}, sender)
- if loopoff == true then
- return false, commandtab[1], sender, "nea"
- end
- 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
- if type(UsrDir) ~= "string" then UsrDir = "/.ccftp/Users" end
- if fs.exists(UsrDir.."/"..UsrName) or UsrName == hash.sha256("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
- if type(UsrDir) ~= "string" then UsrDir = "/.ccftp/Users" end
- if not fs.exists(UsrDir.."/"..oUsrName) then return "nsUsr" end
- if fs.exists(UsrDir.."/"..nUsrName) or nUsrName == hash.sha256("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
- if type(UsrDir) ~= "string" then UsrDir = "/.ccftp/Users" end
- 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 true 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
- if type(UsrDir) ~= "string" then UsrDir = "/.ccftp/Users" end
- 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
- ---- Client Functions ----
- -- gets the Directory Tree for the specified Subdirectory (optional)
- function getDirCont(Hostname, UsrName, UsrPass, Subdir)
- local servver = getServerVer(Hostname)
- if Hostname == nil then
- return "nHn"
- elseif UsrName == nil then
- return "nUsrN"
- elseif UsrPass == nil then
- return "nUsrP"
- elseif servver ~= ccFTPRev then
- if servver:find("Rev") then
- return "wSV"
- else
- return servver
- end
- end
- Subdir = Subdir or ""
- checkAPI()
- if checkModem() then
- local key, iv = unfoldkeyC(UsrPass)
- local hosterID = sendMessageC(Hostname, UsrName, hash.sha256("iv"..iv[15]), ccFTPRev, ccaes.encrypt_str(textutils.serialize({"DirCont", Subdir}), key, iv))
- if hosterID then
- local response, senderID = waitForMessage("C")
- if senderID == hosterID then
- if response[1] == true then
- local resd = ccaes.decrypt_str(response[2], key, iv)
- if response[3] ~= nil then
- return textutils.unserialize(resd), textutils.unserialize(ccaes.decrypt_str(response[3], key, iv))
- else
- return resd
- end
- else
- return response[2]
- 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"
- elseif getServerVer(Hostname) ~= ccFTPRev then
- return "wSV"
- end
- checkAPI()
- if checkModem() then
- local key, iv = unfoldkeyC(UsrPass)
- local hosterID = sendMessageC(Hostname, UsrName, hash.sha256("iv"..iv[15]),ccFTPRev, ccaes.encrypt_str(textutils.serialize({"getFile", FileHost}), key, iv))
- 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
- elseif response[1] == true then
- return ccaes.decrypt_str(response[2], key, iv)
- else
- return response[2]
- 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"
- elseif getServerVer(Hostname) ~= ccFTPRev then
- return "wSV"
- 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]), ccFTPRev, ccaes.encrypt_str(textutils.serialize({"pushFile", FileHost, fileData}), key, iv))
- if hosterID then
- local response, senderID = waitForMessage("C")
- if senderID == hosterID then
- if response[1] == true then
- local resd = ccaes.decrypt_str(response[2], key, iv)
- if resd == "OK" then
- return true
- else
- return resd
- end
- else
- return response[2]
- 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"
- elseif getServerVer(Hostname) ~= ccFTPRev then
- return "wSV"
- end
- checkAPI()
- if checkModem() then
- local key, iv = unfoldkeyC(UsrPass)
- local hosterID = sendMessageC(Hostname, UsrName, hash.sha256("iv"..iv[15]), ccFTPRev, ccaes.encrypt_str(textutils.serialize({"delFile", FileHost}), key, iv))
- if hosterID then
- local response, senderID = waitForMessage("C")
- if senderID == hosterID then
- if response[1] == true then
- local resd = ccaes.decrypt_str(response[2], key, iv)
- if resd == "OK" then
- return true
- else
- return resd
- end
- else
- return response[2]
- 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