Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --Thanks to Valithor for the encryption and hashing API
- if fs.exists("/encrypt.lua") then
- os.loadAPI("/encrypt.lua")
- else
- shell.run("pastebin get cyiVcsMm /encrypt.lua")
- os.loadAPI("/encrypt.lua")
- end
- if fs.exists("/hash.lua") then
- os.loadAPI("/hash.lua")
- else
- shell.run("pastebin get fd9W1x9y /hash.lua")
- os.loadAPI("/hash.lua")
- end
- relay = peripheral.wrap("right")
- modem = peripheral.wrap("top")
- sides = {bottom=0, top=1, back=2, front=3, right=4, left=5}
- alphabet = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"}
- vaultSides = {sides.top, sides.left, sides.right, sides.back, sides.front}
- debug = false
- extension = ".coin"
- boxExt = ".box"
- baseCoin = "gc"
- atmPort = 8374
- subKeyLength = 16
- screenX, screenY = term.getSize()
- blank = string.rep(" ", screenX)
- if not debug then
- input = window.create(term.native(), 1, screenY, screenX, 1)
- info = window.create(term.native(), 1, 1, screenX, screenY-1)
- term.clear()
- term.redirect(input)
- end
- --[[
- Console & Misc Functions
- --]]
- function cPrint(txt)
- if not debug then
- term.redirect(info)
- print(txt)
- term.redirect(input)
- term.setCursorPos(1,1)
- else
- print(txt)
- end
- end
- function worldTime()
- return os.day() + (os.time() * (25/600))
- end
- --[[
- Coin Functions
- --]]
- function addCoin(coinName)
- local f = fs.open("/bank/coins/" .. coinName .. extension, "w")
- local coinData = {}
- coinData["id"] = coinName
- coinData["enabled"] = false
- coinData["worth"] = 0
- coinData["name"] = "Undefined Coin"
- coinData["short"] = "uc"
- coinData["material"] = "Undefined"
- f.write(textutils.serialize(coinData))
- f.close()
- return coinData
- end
- function getCoin(coinName)
- local f = fs.open("/bank/coins/" .. coinName .. extension, "r")
- local coinData = textutils.unserialize(f.readAll())
- f.close()
- return coinData
- end
- function findCoin(coinDescription)
- if coins[coinDescription:lower()] then
- return coins[coinDescription:lower()]
- end
- for k, coinVal in pairs(coins) do
- if coinVal["short"]:lower() == coinDescription:lower() then
- return coinVal
- elseif coinVal["material"]:lower() == coinDescription:lower() then
- return coinVal
- end
- end
- return false
- end
- --[[
- Deposit Box Functions
- --]]
- --KILL
- --ME
- --[[
- Withdraw Box Functions
- --]]
- function addWithdrawBox(boxUuid, side)
- local f = fs.open("/bank/withdrawbox/" .. boxUuid .. tostring(side) .. boxExt, "w")
- local boxData = {}
- boxData["uuid"] = boxUuid
- boxData["name"] = "Undefined Withdraw Box"
- boxData["id"] = "UWB-1"
- boxData["side"] = side
- f.write(textutils.serialize(boxData))
- f.close()
- return boxData
- end
- function getWithdrawBox(boxUuid)
- local f = fs.open("/bank/withdrawbox/" .. boxUuid .. boxExt, "r")
- local boxData = textutils.unserialize(f.readAll())
- f.close()
- return boxData
- end
- function findWithdrawBox(boxDescription)
- local boxDescription = boxDescription:lower()
- if withdrawBoxes[boxDescription] then
- return withdrawBoxes[boxDescription]
- end
- for _, boxVal in pairs(withdrawBoxes) do
- if boxVal["id"]:lower() == boxDescription then
- return boxVal
- elseif boxVal["name"]:lower() == boxDescription then
- return boxVal
- end
- end
- return false
- end
- --[[
- Coin Stock Functions
- --]]
- function saveStock(stock)
- local f = fs.open("/bank/stock.table","w")
- f.write(textutils.serialize(stock))
- f.close()
- end
- --[[
- Communication / ATM Registry Functions
- --]]
- function validATM(atmId)
- for _, atm in atms do
- if atm:lower() == atmId:lower() then
- return true
- end
- end
- return false
- end
- function randomAlpha(length)
- local txt = ""
- for i = 1, length do
- txt = txt .. alphabet[math.random(1,26)]
- end
- return txt
- end
- --[[
- Bank User Functions
- --]]
- function userExists(username)
- return fs.exists("/bank/users/" .. username:lower())
- end
- function createUser(username, password)
- local username = username:lower()
- if not userExists(username) then
- fs.makeDir("/bank/users/" .. username)
- local userPath = "/bank/users/" .. username .. "/"
- local salt = randomAlpha(16)
- local hashedPassword = hash.hash(password, salt)
- local authInfo = {}
- authInfo["password"] = hashedPassword
- authInfo["salt"] = salt
- authInfo["username"] = username
- local f = fs.open(userPath .. "auth","w")
- f.write(textutils.serialize(authInfo))
- f.close()
- local f = fs.open(userPath .. "balance","w")
- f.write("0")
- f.close()
- return true
- else
- return false
- end
- end
- function removeUser(username)
- if userExists(username) then
- fs.delete("/bank/users/" .. username)
- return true
- else
- return false
- end
- end
- function getBalance(username)
- local username = username:lower()
- if userExists(username) then
- local f = fs.open("/bank/users/" .. username .. "/balance","r")
- local balance = tonumber(f.readAll())
- f.close()
- return balance
- end
- return false
- end
- function setBalance(username, newBalance)
- local username = username:lower()
- if userExists(username) then
- local f = fs.open("/bank/users/" .. username .. "/balance","w")
- f.write(tostring(newBalance))
- f.close()
- return newBalance
- end
- return false
- end
- function addBalance(username, amount)
- local username = username:lower()
- local amount = tonumber(amount)
- if userExists(username) then
- local curBalance = getBalance(username)
- local newBalance = curBalance + amount
- return setBalance(username, newBalance)
- end
- return false
- end
- function handleDeposit(atmId, username)
- if userExists(username) then
- local depBox = findDepositBox(atmId)
- if depBox then
- local depositItems = getAllStacks(depBox["uuid"], sides.top)
- local chestSizeBelow = getInventorySize(depBox["uuid"], sides.bottom)
- local chestSlot = 0
- local careful = false
- for i = #depositItems, 1, -1 do
- chestSlot = chestSlot + 1
- if chestSlot > chestSizeBelow then
- chestSlot = 1
- careful = true
- end
- if careful == true then
- while getStackInSlot(depBox["uuid"],sides.bottom,1) ~= nil do
- sleep(0.5)
- end
- end
- local coinData = depositItems[i]
- local coinName = coinData["name"]:gsub("%W","") .. coinData["damage"]
- if findCoin(coinName) then
- local coinObj = findCoin(coinName)
- transferItem(depBox["uuid"], sides.top, sides.bottom, coinData["size"], coinData["slot"], chestSlot)
- stock[coinName] = stock[coinName] + coinData["size"]
- addBalance(username, coinObj["worth"] * coinData["size"])
- saveStock(stock)
- end
- end
- end
- end
- end
- function handleWithdraw(atmId, username, withdrawCoins)
- if userExists(username) then
- end
- end
- --[[
- Transposer Functions
- --]]
- function getInventorySize(uuid, side)
- return relay.callRemote(uuid, "getInventorySize", side)
- end
- function getAllStacks(uuid, side)
- local nilStacks = 0
- local maxNilStacks = 5
- local stacks = {}
- local maxStacks = getInventorySize(uuid, side)
- for i = 1, maxStacks do
- local curStack = getStackInSlot(uuid, side, i)
- if curStack == nil then
- nilStacks = nilStacks + 1
- if nilStacks >= maxNilStacks then
- break
- end
- else
- curStack["slot"] = i
- table.insert(stacks, curStack)
- end
- end
- return stacks
- end
- function transferItem(uuid, source, sink, count, sourceSlot, sinkSlot)
- return relay.callRemote(uuid, "transferItem", source, sink, count, sourceSlot, sinkSlot)
- end
- function getStackInSlot(uuid, side, slot)
- return relay.callRemote(uuid, "getStackInSlot", side, slot)
- end
- --[[
- Initialization
- --]]
- transposers = {}
- tVaults = {}
- tDeposits = {}
- tWithdraws = {}
- for k, uuid in pairs(relay.getNamesRemote()) do
- if relay.getTypeRemote(uuid) == "transposer" then
- table.insert(transposers, uuid)
- if getInventorySize(uuid, sides.bottom) and getInventorySize(uuid, sides.bottom) then
- if not getInventorySize(uuid, sides.top) or getInventorySize(uuid, sides.top) < 5 then
- table.insert(tVaults, uuid)
- else
- table.insert(tDeposits, uuid)
- end
- else
- table.insert(tWithdraws, uuid)
- end
- end
- end
- cPrint("Found " .. tostring(#tVaults) .. " tVaults")
- cPrint("Found " .. tostring(#tDeposits) .. " tDeposits")
- cPrint("Found " .. tostring(#tWithdraws) .. " tWithdraws")
- vaults = {}
- cPrint("Discovering coin storage...")
- for k, transposer in pairs(tVaults) do
- for kb, side in pairs(vaultSides) do
- if getInventorySize(transposer, side) and getInventorySize(transposer, side) == 3 then
- coinInfo = getStackInSlot(transposer, side, 3)
- vaultInfo = {}
- vaultInfo["transposer"] = transposer
- vaultInfo["side"] = side
- vaultInfo["coin"] = coinInfo["name"] .. "#" .. tostring(coinInfo["damage"])
- table.insert(vaults, vaultInfo)
- end
- end
- end
- cPrint("Found " .. tostring(#vaults) .. " coins.")
- if not fs.exists("/bank") or not fs.isDir("/bank") then
- if fs.exists("/bank") then
- fs.delete("/bank")
- end
- fs.makeDir("/bank/")
- cPrint("Created /bank")
- end
- stock = {}
- if not fs.exists("/bank/stock.table") or fs.isDir("/bank/stock.table") then
- if fs.exists("/bank/stock.table") then
- fs.remove("/bank/stock.table")
- end
- for k, coin in pairs(vaults) do
- coinName = coin["coin"]:gsub("%W","")
- stock[coinName] = 0
- end
- cPrint("Created stock table file.")
- saveStock(stock)
- else
- f = fs.open("/bank/stock.table","r")
- stock = textutils.unserialize(f.readAll())
- f.close()
- cPrint("Loaded stock")
- end
- if not fs.exists("/bank/coins") or not fs.isDir("/bank/coins") then
- if fs.exists("/bank/coins") then
- fs.delete("/bank/coins")
- end
- cPrint("Initializing coin directory...")
- fs.makeDir("/bank/coins")
- for _, coin in pairs(vaults) do
- coinName = coin["coin"]:gsub("%W","")
- addCoin(coinName)
- stock[coinName] = 0
- end
- saveStock(stock)
- end
- coins = {}
- cPrint("Loading coins...")
- for _, coin in pairs(vaults) do
- local coinName = coin["coin"]:gsub("%W","")
- if not fs.exists("/bank/coins/" .. coinName .. extension) then
- coins[coinName] = addCoin(coinName)
- stock[coinName] = 0
- saveStock(stock)
- cPrint("Initialized missing coin " .. coinName)
- else
- coins[coinName] = getCoin(coinName)
- end
- end
- cPrint("Loaded coins")
- if not fs.exists("/bank/depositbox/") or not fs.isDir("/bank/depositbox/") then
- if fs.exists("/bank/depositbox/") then
- fs.delete("/bank/depositbox/")
- end
- fs.makeDir("/bank/depositbox/")
- cPrint("Made folder for deposit boxes!")
- end
- depositBoxes = {}
- cPrint("Loading deposit boxes...")
- if not fs.exists("/bank/withdrawbox/") or not fs.isDir("/bank/withdrawbox/") then
- if fs.exists("/bank/withdrawbox/") then
- fs.delete("/bank/withdrawbox/")
- end
- fs.makeDir("/bank/withdrawbox/")
- end
- withdrawBoxes = {}
- for _, tWithdraw in pairs(tWithdraws) do
- for _, side in pairs(sides) do
- if getInventorySize(tWithdraw, side) and getInventorySize(tWithdraw, side) > 54 then
- if fs.exists("/bank/withdrawbox/" .. tWithdraw .. tostring(side)) then
- table.insert(withdrawBoxes, getWithdrawBox(tWithdraw, side))
- else
- table.insert(withdrawBoxes, addWithdrawBox(tWithdraw, side))
- end
- end
- end
- end
- cPrint("Loaded withdraw boxes.")
- atms = {}
- if not fs.exists("/bank/atms.table") or fs.isDir("/bank/atms.table") then
- if fs.exists("/bank/atms.table") then
- fs.delete("/bank/atms.table")
- end
- f = fs.open("/bank/atms.table", "w")
- f.write("{}")
- f.close()
- else
- f = fs.open("/bank/atms.table", "r")
- atms = textutils.unserialize(f.readAll())
- f.close()
- end
- print("Loaded ATMs")
- if not fs.exists("/bank/users") or not fs.isDir("/bank/users") then
- if fs.exists("/bank/users") then
- fs.delete("/bank/users")
- end
- fs.makeDir("/bank/users")
- end
- print("Setting up server...")
- f = fs.open("/bank/atm.key","r")
- key = f.readAll()
- f.close()
- modem.open(atmPort)
- cPrint("Initialization complete, starting server...")
- --[[
- Console Commands
- --]]
- commands = {}
- commands["help"] = {func=function(args)
- if args[2] then
- if commands[args[2]] then
- local helpText = commands[args[2]]["help"]
- helpText = string.gsub(helpText, "%%CMD", args[2])
- cPrint(helpText)
- else
- cPrint("Command not found.")
- end
- else
- local commandList = ""
- for k, v in pairs(commands) do
- commandList = commandList .. k .. " | "
- end
- cPrint("Available commands: ")
- cPrint(commandList)
- cPrint("For help on a command, use help <cmd>")
- end
- end, help="Usage: %CMD [CMD]"}
- commands["coin"] = {func=function(args)
- if args[2] then
- if args[2] == "list" then
- local coinList = ""
- for k, v in pairs(coins) do
- coinList = coinList .. v["name"] .. " (" .. v["id"] .. ") | "
- end
- cPrint("Coins: " .. coinList)
- elseif args[2] == "info" then
- if args[3] then
- local coin = findCoin(args[3])
- if coin then
- cPrint(coin["name"])
- cPrint("Enabled: " .. tostring(coin["enabled"]))
- cPrint("Worth: " .. tostring(coin["worth"]) .. "gc")
- cPrint("Material: " .. tostring(coin["material"]))
- cPrint("Currency Code: " .. tostring(coin["short"]))
- cPrint("Id: " .. tostring(coin["id"]))
- else
- cPrint("Unknown coin, usage: info <coin id/material/code>")
- end
- else
- cPrint("Invalid argument, usage: info <coin>")
- end
- else
- cPrint("Invalid subcommand, valid subcommands: list, info")
- end
- else
- cPrint("No subcommand, valid subcommands: list, info")
- end
- end, help="Usage: %CMD <list | info>"}
- commands["user"] = {func=function(args)
- if args[2] then
- if args[2] == "create" then
- if args[3] and args[4] then
- tryCreate = createUser(args[3],args[4])
- cPrint("Create user " .. args[3] .. ": " .. tostring(tryCreate))
- else
- cPrint("Usage: create <username> <password>")
- end
- elseif args[2] == "remove" then
- if args[3] then
- tryRemove = removeUser(args[3])
- cPrint("Removed user " .. args[3] .. ": " .. tostring(tryRemove))
- else
- cPrint("Usage: remove <username>")
- end
- elseif args[2] == "balance" then
- if args[3] then
- if args[4] then
- if args[4] == "set" and tonumber(args[5]) then
- cPrint(args[3] .. "'s new balance: " .. tostring(setBalance(args[3], tonumber(args[5]))))
- elseif args[4] == "add" and tonumber(args[5]) then
- cPrint(args[3] .. "'s new balance: " .. tostring(addBalance(args[3], tonumber(args[5]))))
- else
- cPrint("Usage: balance <user> <set | add> <amount>")
- end
- else
- cPrint(args[3] .. "'s balance: " .. tostring(getBalance(args[3])))
- end
- else
- cPrint("Usage: balance <user> [set | add]")
- end
- else
- cPrint("Invalid subcommand, valid subcommands: create, remove, balance")
- end
- else
- cPrint("No subcommand, valid subcommands: create, remove, balance")
- end
- end, help="Usage: %CMD <create | remove | balance>"}
- commands["test"] = {func=function(args)
- if args[2] then
- if args[2] == "deposit" then
- if args[3] and args[4] then
- handleDeposit(args[3], args[4])
- else
- cPrint("Usage: deposit <atmId> <username>")
- end
- else
- cPrint("Invalid subcommand, valid subcommands: deposit")
- end
- else
- cPrint("No subcommand, valid subcommands: deposit")
- end
- end, help="Usage: %CMD <deposit>"}
- function console()
- --[[
- Controls the console
- --]]
- while true do
- if not debug then
- term.redirect(input)
- end
- term.setCursorPos(1,1)
- term.write(blank)
- term.setCursorPos(1,1)
- term.write("> ")
- local cmd = read()
- if cmd:lower() == "exit" then
- break
- else
- local cArgs = {}
- for arg in cmd:gmatch("%S+") do table.insert(cArgs, arg) end
- if commands[cArgs[1]:lower()] then
- commands[cArgs[1]:lower()]["func"](cArgs)
- end
- end
- end
- return
- end
- function server()
- --[[
- Controls the server / communications
- --]]
- local subKeys = {}
- while true do
- local e = { os.pullEvent("modem_message") }
- if e[2] == "top" and e[3] == atmPort then
- --Received ATM Message
- if e[5] and e[5]["id"] and validATM(e[5]["id"]) and e[5]["msg"] and subKeys[e[5]["id"]] then
- --Valid ATM Message
- local atmId = e[5]["id"]
- local atmMessage = encrypt.decrypt(e[5]["msg"], key .. subKeys[atmId])
- if atmMessage:sub(1,1) == "{" and atmMessage:sub(#atmMessage, #atmMessage) == "}" then
- local newKey = randomAlpha(subKeyLength)
- atmMessage = textutils.unserialize(encrypt.decrypt(e[5]["msg"], key))
- if atmMessage["op"] then
- --atmMessage decoded & Valid
- local op = atmMessage["op"]
- if op == "deposit" then
- if atmMessage["user"] then
- if userExists(atmMessage["user"]) then
- handleDeposit(atmId, atmMessage["user"])
- local respMsg = {newKey=newKey, success=true}
- local encMsg = encrypt.encrypt(textutils.serialize(respMsg), key .. subKeys[atmId])
- subKeys[atmId] = newKey
- modem.transmit(atmPort, 200, {to=atmId, op="depositStarted", msg=encMsg})
- else
- local respMsg = {newKey=newKey, error="Invalid User."}
- local encMsg = encrypt.encrypt(textutils.serialize(respMsg), key .. subKeys[atmId])
- subKeys[atmId] = newKey
- modem.transmit(atmPort, 400, {to=atmId, op="error", msg=encMsg})
- end
- else
- local respMsg = {newKey=newKey, error="No user supplied."}
- local encMsg = encrypt.encrypt(textutils.serialize(respMsg), key .. subKeys[atmId])
- subKeys[atmId] = newKey
- modem.transmit(atmPort, 400, {to=atmId, op="error", msg=encMsg})
- end
- elseif op == "withdraw" then
- if atmMessage["user"] and userExists(atmMessage["user"]) then
- if atmMessage["coins"] then
- handleWithdraw(atmId, atmMessage["user"], atmMessage["coins"])
- local respMsg = {newKey=newKey, success=true}
- local encMsg = encrypt.encrypt(textutils.serialize(respMsg), key .. subKeys[atmId])
- subKeys[atmId] = newKey
- modem.transmit(atmPort, 200, {to=atmId, op="withdrawStarted", msg=encMsg})
- else
- local respMsg = {newKey=newKey, error="No coins specified."}
- local encMsg = encrypt.encrypt(textutils.serialize(respMsg), key .. subKeys[atmId])
- subKeys[atmId] = newKey
- modem.transmit(atmPort, 400, {to=atmId, op="error", msg=encMsg})
- end
- else
- local respMsg = {newKey=newKey, error="Invalid or missing user."}
- local encMsg = encrypt.encrypt(textutils.serialize(respMsg), key .. subKeys[atmId])
- subKeys[atmId] = newKey
- modem.transmit(atmPort, 400, {to=atmId, op="error", msg=encMsg})
- end
- elseif op == "newUser" then
- if atmMessage["username"] and atmMessage["password"] then
- local username = atmMessage["username"]
- local password = atmMessage["password"]
- if createUser(username, password) then
- local respMsg = {newKey=newKey, success=true, username=username}
- local encMsg = encrypt.encrypt(textutils.serialize(respMsg), key .. subKeys[atmId])
- subKeys[atmId] = newKey
- modem.transmit(atmPort, 200, {to=atmId, op="accountCreated", msg=encMsg})
- else
- local respMsg = {newKey=newKey, error="Could not create account."}
- local encMsg = encrypt.encrypt(textutils.serialize(respMsg), key .. subKeys[atmId])
- subKeys[atmId] = newKey
- modem.transmit(atmPort, 400, {to=atmId, op="error", msg=encMsg})
- end
- else
- local respMsg = {newKey=newKey, error="Missing username or password..."}
- local encMsg = encrypt.encrypt(textutils.serialize(respMsg), key .. subKeys[atmId])
- subKeys[atmId] = newKey
- modem.transmit(atmPort, 400, {to=atmId, op="error", msg=encMsg})
- end
- else
- local respMsg = {newKey=newKey, error="Invalid operation!"}
- local encMsg = encrypt.encrypt(textutils.serialize(respMsg), key .. subKeys[atmId])
- subKeys[atmId] = newKey
- modem.transmit(atmPort, 400, {to=atmId, op="error", msg=encMsg})
- end
- else
- --Message decoded, but not valid.
- local respMsg = {newKey=newKey, error="Invalid message"}
- local encMsg = encrypt.encrypt(textutils.serialize(respMsg), key .. subKeys[atmId])
- subKeys[atmId] = newKey
- modem.transmit(atmPort, 400, {to=atmId, op="error", msg=encMsg})
- end
- else
- modem.transmit(atmPort, 400, {to=atmId, op="error", umsg={erorr="Decryption error"}})
- --Decryption error
- end
- elseif e[5] and e[5]["id"] and e[5]["getKey"] then
- local atmId = e[5]["id"]
- subKeys[atmId] = randomAlpha(subKeyLength)
- local respMsg = {newKey=subKeys[atmId]}
- local encMsg = encrypt.encrypt(textutils.serialize(respMsg), key .. e[5]["getKey"])
- modem.transmit(atmPort,100, {to=atmId, op="newKey", msg=encMsg})
- end
- end
- end
- end
- parallel.waitForAny(console, server)
Advertisement
Add Comment
Please, Sign In to add comment