Added bank-client, secure commands
This commit is contained in:
parent
da47304eec
commit
b7ecf7681e
|
@ -0,0 +1,106 @@
|
||||||
|
--[[
|
||||||
|
The bank-client is a library that applications can include to interact with
|
||||||
|
a central bank server. Note that it functions over the Rednet protocol, so you
|
||||||
|
should call `rednet.open("modem-name")` first.
|
||||||
|
]]--
|
||||||
|
|
||||||
|
local client = {}
|
||||||
|
|
||||||
|
client.state = {
|
||||||
|
auth = nil,
|
||||||
|
hostId = nil,
|
||||||
|
timeout = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
local function requestRaw(msg)
|
||||||
|
if not client.state.hostId or not rednet.isOpen() then
|
||||||
|
return {success = false, error = "Client not initialized"}
|
||||||
|
end
|
||||||
|
rednet.send(client.state.hostId, msg, "BANK")
|
||||||
|
local remoteId, response = rednet.receive("BANK", client.state.timeout)
|
||||||
|
if not remoteId then
|
||||||
|
return {success = false, error = "Request timed out"}
|
||||||
|
end
|
||||||
|
return response
|
||||||
|
end
|
||||||
|
|
||||||
|
local function request(command, data)
|
||||||
|
return requestRaw({command = command, data = data})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function requestAuth(command, data)
|
||||||
|
if not client.loggedIn() then
|
||||||
|
return {success = false, error = "Client not logged in"}
|
||||||
|
end
|
||||||
|
return requestRaw({command = command, auth = client.state.auth, data = data})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Base functions
|
||||||
|
|
||||||
|
function client.init(modemName, host)
|
||||||
|
rednet.open(modemName)
|
||||||
|
client.state.hostId = rednet.lookup("BANK", host)
|
||||||
|
return client.state.hostId ~= nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function client.logIn(username, password)
|
||||||
|
client.state.auth = {username = username, password = password}
|
||||||
|
end
|
||||||
|
|
||||||
|
function client.logOut()
|
||||||
|
client.state.auth = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function client.loggedIn()
|
||||||
|
return client.state.auth ~= nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- BANK functions
|
||||||
|
|
||||||
|
function client.getStatus()
|
||||||
|
local response = request("STATUS")
|
||||||
|
return response.success, response.error
|
||||||
|
end
|
||||||
|
|
||||||
|
function client.createUser(username, password)
|
||||||
|
local response = request("CREATE_USER", {username = username, password = password})
|
||||||
|
return response.success, response.error
|
||||||
|
end
|
||||||
|
|
||||||
|
function client.deleteUser()
|
||||||
|
local response = requestAuth("DELETE_USER")
|
||||||
|
return response.success
|
||||||
|
end
|
||||||
|
|
||||||
|
function client.renameUser(newUsername)
|
||||||
|
local response = requestAuth("RENAME_USER", {newUsername = newUsername})
|
||||||
|
return response.success, response.error
|
||||||
|
end
|
||||||
|
|
||||||
|
function client.getAccounts()
|
||||||
|
local response = requestAuth("GET_ACCOUNTS")
|
||||||
|
if not response.success then
|
||||||
|
return nil, response.error
|
||||||
|
end
|
||||||
|
return response.data
|
||||||
|
end
|
||||||
|
|
||||||
|
function client.createAccount(accountName)
|
||||||
|
local response = requestAuth("CREATE_ACCOUNT", {name = accountName})
|
||||||
|
if not response.success then
|
||||||
|
return nil, response.error
|
||||||
|
end
|
||||||
|
return response.data
|
||||||
|
end
|
||||||
|
|
||||||
|
function client.deleteAccount(accountId)
|
||||||
|
local response = requestAuth("DELETE_ACCOUNT", {accountId = accountId})
|
||||||
|
return response.success
|
||||||
|
end
|
||||||
|
|
||||||
|
function client.renameAccount(accountId, newName)
|
||||||
|
local response = requestAuth("RENAME_ACCOUNT", {accountId = accountId, newName = newName})
|
||||||
|
return response.success, response.error
|
||||||
|
end
|
||||||
|
|
||||||
|
return client
|
51
bank.lua
51
bank.lua
|
@ -28,6 +28,22 @@ local function log(msg)
|
||||||
g.appendAndDrawConsole(term, console, textutils.formatTime(os.time()) .. ": " .. msg, 1, 3)
|
g.appendAndDrawConsole(term, console, textutils.formatTime(os.time()) .. ": " .. msg, 1, 3)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Initialize security key
|
||||||
|
local SECURITY_KEY_FILE = "key.txt"
|
||||||
|
local SECURITY_KEY = nil
|
||||||
|
if not fs.exists(SECURITY_KEY_FILE) then
|
||||||
|
local f = io.open(SECURITY_KEY_FILE, "w")
|
||||||
|
SECURITY_KEY = randomAccountId() .. "-" .. randomAccountId() .. "-" .. randomAccountId()
|
||||||
|
f:write(SECURITY_KEY)
|
||||||
|
f:close()
|
||||||
|
log("Generated new security key.")
|
||||||
|
else
|
||||||
|
local f = io.open(SECURITY_KEY_FILE, "r")
|
||||||
|
SECURITY_KEY = f:read("*a")
|
||||||
|
f:close()
|
||||||
|
log("Loaded stored security key.")
|
||||||
|
end
|
||||||
|
|
||||||
-- Helper functions
|
-- Helper functions
|
||||||
|
|
||||||
local function readJSON(filename)
|
local function readJSON(filename)
|
||||||
|
@ -119,7 +135,7 @@ local function createAccount(username, accountName)
|
||||||
table.insert(accounts, newAccount)
|
table.insert(accounts, newAccount)
|
||||||
saveAccounts(username, accounts)
|
saveAccounts(username, accounts)
|
||||||
log("Created account " .. newAccount.id .. " for user " .. username)
|
log("Created account " .. newAccount.id .. " for user " .. username)
|
||||||
return true, newAccount.id
|
return true, newAccount
|
||||||
end
|
end
|
||||||
|
|
||||||
local function deleteAccount(username, accountId)
|
local function deleteAccount(username, accountId)
|
||||||
|
@ -193,7 +209,7 @@ end
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
-- Helper function to wrap another function in an authentication check.
|
-- Helper function to wrap another function in an authentication check.
|
||||||
local function authProtect(func)
|
local function authProtect(func, secure)
|
||||||
return function (msg)
|
return function (msg)
|
||||||
if (
|
if (
|
||||||
not msg.auth or
|
not msg.auth or
|
||||||
|
@ -204,10 +220,17 @@ local function authProtect(func)
|
||||||
) then
|
) then
|
||||||
return {success = false, error = "Invalid credentials"}
|
return {success = false, error = "Invalid credentials"}
|
||||||
end
|
end
|
||||||
|
if secure and (not msg.auth.key or msg.auth.key ~= SECURITY_KEY) then
|
||||||
|
return {success = false, error = "Missing security key"}
|
||||||
|
end
|
||||||
return func(msg)
|
return func(msg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function handleGetStatus(msg)
|
||||||
|
return {success = true}
|
||||||
|
end
|
||||||
|
|
||||||
local function handleCreateUser(msg)
|
local function handleCreateUser(msg)
|
||||||
if not msg.data or not msg.data.username or not msg.data.password then
|
if not msg.data or not msg.data.username or not msg.data.password then
|
||||||
return {success = false, error = "Invalid request. Requires data.username and data.password."}
|
return {success = false, error = "Invalid request. Requires data.username and data.password."}
|
||||||
|
@ -239,6 +262,17 @@ local function handleGetUserAccounts(msg)
|
||||||
return {success = true, data = getAccounts(msg.auth.username)}
|
return {success = true, data = getAccounts(msg.auth.username)}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function handleCreateUserAccount(msg)
|
||||||
|
if not msg.data or not msg.data.name then
|
||||||
|
return {success = false, error = "Invalid request. Requires data.name."}
|
||||||
|
end
|
||||||
|
local success, errorOrAccount = createAccount(msg.auth.username, msg.data.name)
|
||||||
|
if not success then
|
||||||
|
return {success = false, error = errorOrAccount}
|
||||||
|
end
|
||||||
|
return {success = true, data = errorOrAccount}
|
||||||
|
end
|
||||||
|
|
||||||
local function handleDeleteUserAccount(msg)
|
local function handleDeleteUserAccount(msg)
|
||||||
if not msg.data or not msg.data.accountId then
|
if not msg.data or not msg.data.accountId then
|
||||||
return {success = false, error = "Invalid request. Requires data.accountId."}
|
return {success = false, error = "Invalid request. Requires data.accountId."}
|
||||||
|
@ -255,12 +289,15 @@ local function handleRenameUserAccount(msg)
|
||||||
return {success = success, error = errorMsg}
|
return {success = success, error = errorMsg}
|
||||||
end
|
end
|
||||||
|
|
||||||
local function BANK_REQUESTS = {
|
-- A registry of all possible BANK requests, and their handler functions.
|
||||||
|
local BANK_REQUESTS = {
|
||||||
|
["STATUS"] = handleGetStatus,
|
||||||
["CREATE_USER"] = handleCreateUser,
|
["CREATE_USER"] = handleCreateUser,
|
||||||
["DELETE_USER"] = authProtect(handleDeleteUser)
|
["DELETE_USER"] = authProtect(handleDeleteUser),
|
||||||
["RENAME_USER"] = authProtect(handleRenameUser)
|
["RENAME_USER"] = authProtect(handleRenameUser),
|
||||||
["GET_ACCOUNTS"] = authProtect(handleGetUserAccounts)
|
["GET_ACCOUNTS"] = authProtect(handleGetUserAccounts),
|
||||||
["DELETE_ACCOUNT"] = authProtect(handleDeleteUserAccount)
|
["CREATE_ACCOUNT"] = authProtect(handleCreateUserAccount),
|
||||||
|
["DELETE_ACCOUNT"] = authProtect(handleDeleteUserAccount),
|
||||||
["RENAME_ACCOUNT"] = authProtect(handleRenameUserAccount)
|
["RENAME_ACCOUNT"] = authProtect(handleRenameUserAccount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue