kp-bank/atm.lua

190 lines
7.1 KiB
Lua
Raw Normal View History

2023-08-29 20:53:57 +00:00
--[[
atm.lua is a client program that runs on a computer connected to a backing
currency supply, to facilitate deposits and withdrawals as well as other
banking actions.
Each ATM keeps a secret security key that it uses to authorize secure actions
like recording transactions.
]]--
local g = require("simple-graphics")
local bankClient = require("bank-client")
2023-08-29 22:11:55 +00:00
local BANK_HOST = "central-bank"
local SECURITY_KEY = "4514-1691-1660-7358-1884-0506-0878-7098-1511-3359-3602-3581-6910-0791-1843-5936"
local modem = peripheral.find("modem") or error("No modem attached.")
bankClient.init(peripheral.getName(modem), BANK_HOST, SECURITY_KEY)
2023-08-29 20:53:57 +00:00
local W, H = term.getSize()
local function drawFrame()
g.clear(term, colors.white)
g.drawXLine(term, 1, W, 1, colors.black)
g.drawText(term, 2, 1, "ATM", colors.white, colors.black)
end
2023-08-29 21:25:57 +00:00
local function tryReadDiskCredentials(name)
if disk.hasData(name) then
local dataFile = fs.combine(disk.getMountPath(name), "bank-credentials.json")
if fs.exists(dataFile) then
local f = io.open(dataFile, "r")
local content = textutils.unserializeJSON(f:read("*a"))
f:close()
if (
content ~= nil and
content.username and
type(content.username) == "string" and
content.password and
type(content.password) == "string"
) then
return content
end
end
end
return nil
end
2023-08-29 21:55:48 +00:00
local function tryLoginViaInput()
2023-08-29 20:53:57 +00:00
drawFrame()
2023-08-29 21:55:48 +00:00
g.drawTextCenter(term, W/2, 3, "Enter your username and password below.", colors.black, colors.white)
2023-08-29 22:11:55 +00:00
g.drawText(term, 16, 5, "Username", colors.black, colors.white)
g.drawXLine(term, 16, 34, 6, colors.lightGray)
g.drawText(term, 16, 8, "Password", colors.black, colors.white)
g.drawXLine(term, 16, 34, 9, colors.lightGray)
2023-08-29 21:55:48 +00:00
g.fillRect(term, 22, 11, 9, 3, colors.green)
g.drawTextCenter(term, W/2, 12, "Login", colors.white, colors.green)
g.fillRect(term, 22, 15, 9, 3, colors.red)
g.drawTextCenter(term, W/2, 16, "Cancel", colors.white, colors.red)
local username = ""
local password = ""
local selectedInput = "username"
while true do
local usernameColor = colors.lightGray
if selectedInput == "username" then usernameColor = colors.gray end
2023-08-29 22:11:55 +00:00
g.drawXLine(term, 16, 34, 6, usernameColor)
g.drawText(term, 16, 6, string.rep("*", #username), colors.white, usernameColor)
2023-08-29 21:55:48 +00:00
local passwordColor = colors.lightGray
if selectedInput == "password" then passwordColor = colors.gray end
2023-08-29 22:11:55 +00:00
g.drawXLine(term, 16, 34, 9, passwordColor)
g.drawText(term, 16, 9, string.rep("*", #password), colors.white, passwordColor)
2023-08-29 21:55:48 +00:00
local event, p1, p2, p3 = os.pullEvent()
if event == "char" then
local char = p1
if selectedInput == "username" and #username < 12 then
username = username .. char
elseif selectedInput == "password" and #password < 18 then
password = password .. char
end
elseif event == "key" then
local keyCode = p1
local held = p2
if keyCode == keys.backspace then
if selectedInput == "username" and #username > 0 then
username = string.sub(username, 1, #username - 1)
elseif selectedInput == "password" and #password > 0 then
password = string.sub(password, 1, #password - 1)
end
2023-08-29 22:11:55 +00:00
elseif keyCode == keys.tab and selectedInput == "username" then
selectedInput = "password"
2023-08-29 21:55:48 +00:00
end
elseif event == "mouse_click" then
local button = p1
local x = p2
local y = p3
2023-08-29 22:11:55 +00:00
if y == 6 and x >= 16 and x <= 34 then
2023-08-29 21:55:48 +00:00
selectedInput = "username"
2023-08-29 22:11:55 +00:00
elseif y == 9 and x >= 16 and x <= 34 then
2023-08-29 21:55:48 +00:00
selectedInput = "password"
elseif y >= 11 and y <= 13 and x >= 22 and x <= 30 then
2023-08-29 22:11:55 +00:00
return {username = username, password = password} -- Do login
2023-08-29 21:55:48 +00:00
elseif y >= 15 and y <= 17 and x >= 22 and x <= 30 then
2023-08-29 22:11:55 +00:00
return nil -- Cancel
2023-08-29 21:55:48 +00:00
end
end
end
end
local function showLoginUI()
2023-08-29 21:09:38 +00:00
while true do
2023-08-29 21:55:48 +00:00
drawFrame()
g.drawTextCenter(term, W/2, 3, "Welcome to HandieBank ATM!", colors.green, colors.white)
g.drawTextCenter(term, W/2, 5, "Insert your card below, or click to login.", colors.black, colors.white)
g.fillRect(term, 22, 7, 9, 3, colors.green)
g.drawTextCenter(term, W/2, 8, "Login", colors.white, colors.green)
2023-08-29 21:09:38 +00:00
local event, p1, p2, p3 = os.pullEvent()
if event == "disk" then
2023-08-29 21:25:57 +00:00
local credentials = tryReadDiskCredentials(p1)
if credentials then
return credentials
2023-08-29 21:18:23 +00:00
else
2023-08-29 21:25:57 +00:00
disk.eject(p1)
2023-08-29 21:18:23 +00:00
end
2023-08-29 21:09:38 +00:00
elseif event == "mouse_click" then
local button = p1
local x = p2
local y = p3
2023-08-29 21:25:57 +00:00
if button == 1 and x >= 22 and x <= 30 and y >= 7 and y <= 9 then
2023-08-29 21:55:48 +00:00
local credentials = tryLoginViaInput()
if credentials then return credentials end
2023-08-29 21:09:38 +00:00
end
end
end
2023-08-29 20:53:57 +00:00
end
2023-08-29 22:11:55 +00:00
local function checkCredentialsUI(credentials)
drawFrame()
g.drawTextCenter(term, W/2, 3, "Checking your credentials...", colors.black, colors.white)
2023-08-29 22:24:06 +00:00
os.sleep(1)
2023-08-29 22:11:55 +00:00
bankClient.logIn(credentials.username, credentials.password)
local accounts, errorMsg = bankClient.getAccounts()
if not accounts then
bankClient.logOut()
g.drawTextCenter(term, W/2, 5, errorMsg, colors.red, colors.white)
os.sleep(2)
return false
end
2023-08-29 22:24:06 +00:00
g.drawTextCenter(term, W/2, 5, "Authentication successful.", colors.green, colors.white)
2023-08-29 22:11:55 +00:00
os.sleep(1)
return true
end
2023-08-29 22:24:06 +00:00
local function showAccountsUI()
local accounts, errorMsg = bankClient.getAccounts()
while true do
drawFrame()
g.drawXLine(term, 1, 19, 2, colors.gray)
g.drawText(term, 2, 2, "Account", colors.white, colors.gray)
2023-08-29 22:28:16 +00:00
g.drawXLine(term, 10, 30, 2, colors.lightGray)
g.drawText(term, 11, 2, "Name", colors.white, colors.lightGray)
g.drawXLine(term, 31, W, 2, colors.gray)
g.drawText(term, 32, 2, "Balance ($HMK)", colors.white, colors.gray)
2023-08-29 22:24:06 +00:00
for i, account in pairs(accounts) do
local bg = colors.blue
if i % 2 == 0 then bg = colors.lightBlue end
local fg = colors.white
local y = i + 2
g.drawXLine(term, 1, W, y, bg)
2023-08-29 22:28:16 +00:00
g.drawText(term, 2, y, "..." .. string.sub(account.id, -5, -1), fg, bg)
g.drawText(term, 11, y, account.name, fg, bg)
g.drawText(term, 32, y, tostring(account.balance), fg, bg)
2023-08-29 22:24:06 +00:00
end
local event, button, x, y = os.pullEvent("mouse_click")
if button == 1 and y > 2 and (y - 2) <= #accounts then
-- TODO: Do something.
end
end
end
2023-08-29 21:09:38 +00:00
while true do
local credentials = showLoginUI()
2023-08-29 22:11:55 +00:00
local loginSuccess = checkCredentialsUI(credentials)
if loginSuccess then
2023-08-29 22:28:16 +00:00
showAccountsUI()
2023-08-29 22:11:55 +00:00
end
2023-08-29 21:18:23 +00:00
return
2023-08-29 21:09:38 +00:00
end