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)
g.drawXLine(term, 20, 40, 2, colors.lightGray)
g.drawText(term, 21, 2, "Name", colors.white, colors.lightGray)
g.drawXLine(term, 41, W, 2, colors.gray)
g.drawText(term, 42, 2, "Balance ($HMK)", colors.white, colors.gray)
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)
g.drawText(term, 1, y, account.id, fg, bg)
g.drawText(term, 20, y, account.name, fg, bg)
g.drawText(term, 41, y, tostring(account.balance), fg, bg)
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
print("Login success!")
end
2023-08-29 21:18:23 +00:00
return
2023-08-29 21:09:38 +00:00
end