mirror of
https://github.com/AR2000AR/openComputers_codes.git
synced 2025-09-08 06:31:14 +02:00
303 lines
10 KiB
Lua
303 lines
10 KiB
Lua
local bank = require("bank_api")
|
|
local filesystem = require("filesystem")
|
|
local io = require("io")
|
|
local serialization = require("serialization")
|
|
local event = require("event")
|
|
local libCB = require("libCB")
|
|
local component = require("component")
|
|
local term = require("term")
|
|
local computer = require("computer")
|
|
|
|
local transposer = component.transposer
|
|
local gpu = component.gpu
|
|
local disk_drive = component.disk_drive
|
|
local data = component.data
|
|
|
|
local CONFIG_PATH = "/etc/bank/accountMaker/"
|
|
local CONFIG_FILE = CONFIG_PATH .. "config.cfg"
|
|
local OUT_PATH = "/var/bank/accountMaker/"
|
|
local ACCOUNT_FILE = OUT_PATH .. "accounts.csv"
|
|
local ERROR_FILE = OUT_PATH .. "operr.csv"
|
|
|
|
local config = {}
|
|
local knownAccounts = {}
|
|
local run = true
|
|
|
|
--FUNCTION DECALARATION========================================================
|
|
local function parseCSVLine(line, sep)
|
|
local endReached = false
|
|
local res = {}
|
|
while (not endReached) do
|
|
local i = line:find(sep)
|
|
if (not i) then
|
|
endReached = true
|
|
i = #line + 1
|
|
end
|
|
table.insert(res, line:sub(1, i - 1))
|
|
line = line:sub(i + 1)
|
|
end
|
|
return (res)
|
|
end
|
|
|
|
local function saveConfig()
|
|
--save the config table to a file
|
|
if (config.masterAccountCBdata) then
|
|
---@type string
|
|
config.masterAccountCBdata = data.encode64(serialization.serialize(config.masterAccountCBdata))
|
|
end
|
|
local cFile = io.open(CONFIG_FILE, "w")
|
|
assert(cFile, string.format("Could not open : %s", CONFIG_FILE))
|
|
cFile:write(serialization.serialize(config))
|
|
cFile:close()
|
|
if (config.masterAccountCBdata) then
|
|
---@type cardData
|
|
config.masterAccountCBdata = serialization.unserialize(data.decode64(config.masterAccountCBdata--[[@as string]] ))
|
|
end
|
|
end
|
|
|
|
local function addToKnonwPlayer(playerName, accountUUID)
|
|
--save the player/account list to a file
|
|
local file = io.open(ACCOUNT_FILE, "a")
|
|
assert(file, "Could not append or create " .. ACCOUNT_FILE)
|
|
file:write(string.format("%s,%s\n", playerName, accountUUID))
|
|
file:close()
|
|
table.insert(knownAccounts, {playerName, accountUUID})
|
|
end
|
|
|
|
---Get the player's account uuid if exists
|
|
---@param playerName string
|
|
---@return string|boolean
|
|
local function getAccountUUID(playerName)
|
|
for _, v in ipairs(knownAccounts) do
|
|
if (v[1] == playerName) then return v[2] end
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function moveItem(source, sink, item, amount)
|
|
local function itemFromString(itemString)
|
|
local name, damage = itemString:match("([^:]+:[^:]+):?([0-9]*)")
|
|
if (damage == "") then damage = "0" end
|
|
damage = tonumber(damage)
|
|
return {
|
|
name = name,
|
|
damage = damage,
|
|
label = name:match(":([^:]+)")
|
|
}
|
|
end
|
|
|
|
local function itemEquals(itemA, itemB)
|
|
if (type(itemA) == "string") then itemA = itemFromString(itemA) end
|
|
if (type(itemB) == "string") then itemB = itemFromString(itemB) end
|
|
return itemA.name == itemB.name and itemA.damage == itemB.damage
|
|
end
|
|
|
|
assert(type(source) == "number", "Invalid source side")
|
|
assert(type(sink) == "number", "Invalid sink side")
|
|
assert(item, "No item provided")
|
|
amount = amount or 1
|
|
assert(type(amount) == "number", "number expected")
|
|
local slot = 0
|
|
local request = amount
|
|
for chestItem in transposer.getAllStacks(source) do
|
|
slot = slot + 1
|
|
if (chestItem.name and itemEquals(item, chestItem)) then
|
|
amount = amount - transposer.transferItem(source, sink, amount, slot)
|
|
end
|
|
if (amount <= 0) then break end
|
|
end
|
|
return request - amount
|
|
end
|
|
|
|
---Create a new card for the player
|
|
---@param playerName string
|
|
local function makeCard(playerName)
|
|
term.clear()
|
|
local status
|
|
local newAccount = false
|
|
|
|
--#region getaccount
|
|
|
|
local acUUID = getAccountUUID(playerName)
|
|
if (not acUUID) then
|
|
print("Making a new account")
|
|
newAccount = true
|
|
---@diagnostic disable-next-line: cast-local-type
|
|
status, acUUID = bank.createAccount()
|
|
if (status == 0) then --ok
|
|
addToKnonwPlayer(playerName, acUUID)
|
|
if (config.masterAccountCreditPerAccount ~= 0) then
|
|
status = bank.editAccount(config.masterAccountCBdata--[[@as cardData]] , config.masterAccountCreditPerAccount)
|
|
if (status ~= 0) then
|
|
local file = io.open(ERROR_FILE, "a")
|
|
assert(file, "Can't fail here")
|
|
file:write(string.format("%i,%s,%i\n", status, "master account", config.newAccountCredit))
|
|
file:close()
|
|
end
|
|
end
|
|
else
|
|
print("Server did not respond")
|
|
print("Status : " .. status)
|
|
event.pull("touch")
|
|
return
|
|
end
|
|
end
|
|
|
|
--#endregion
|
|
--#region writeCard
|
|
|
|
if (component.isAvailable("drive")) then
|
|
if (component.drive.getLabel()) then
|
|
disk_drive.eject()
|
|
event.pull("component_unavailable", "drive")
|
|
moveItem(config.sideChest, config.sideDrive, "opencomputers:storage:1", 1)
|
|
end
|
|
end
|
|
if (not component.isAvailable("drive")) then
|
|
moveItem(config.sideChest, config.sideDrive, "opencomputers:storage:1", 1)
|
|
end
|
|
local pin, rawCBdata
|
|
local try = 0
|
|
local goodCB = false
|
|
repeat
|
|
if (not component.isAvailable("drive")) then event.pull("component_available", "drive") end
|
|
print("Requesting CB")
|
|
---@cast acUUID string
|
|
status, pin, rawCBdata = bank.requestNewCBdata(acUUID, component.drive.address)
|
|
if (status ~= 0) then
|
|
print("ERROR : Could not get rawCBdata\nStatus : " .. status)
|
|
else
|
|
assert(rawCBdata, "Status 0 but no rawCBdata")
|
|
print(string.format("PIN : %q", pin))
|
|
print("Writing CB")
|
|
libCB.writeCB(rawCBdata, component.drive)
|
|
goodCB = libCB.getCB(component.drive, pin)
|
|
end
|
|
try = try + 1
|
|
until (goodCB or try >= 3)
|
|
|
|
--#endregion
|
|
--#region initialCredit
|
|
|
|
if (try < 3) then
|
|
if (newAccount) then
|
|
if (config.newAccountCredit ~= 0) then
|
|
print("Giving stating credits")
|
|
status = bank.editAccount(libCB.getCB(component.drive, pin), config.newAccountCredit)
|
|
if (status ~= 0) then
|
|
print("No credit given. Contact admin")
|
|
local file = io.open(ERROR_FILE, "a")
|
|
assert(file, "Can't fail here")
|
|
file:write(string.format("%i,%s,%i\n", status, acUUID, config.newAccountCredit))
|
|
file:close()
|
|
end
|
|
end
|
|
end
|
|
for i = 1, 3 do computer.beep(nil, 0.25) end
|
|
print("Take your card")
|
|
event.pull("component_unavailable", "drive")
|
|
else
|
|
moveItem(config.sideDrive, config.sideChest, "opencomputers:storage:1", 1)
|
|
print("Can't make a card")
|
|
print("Touch to continue")
|
|
event.pull("touch")
|
|
end
|
|
|
|
--#endregion
|
|
end
|
|
|
|
--INIT=========================================================================
|
|
--make directory if missing
|
|
if (not filesystem.isDirectory(CONFIG_PATH)) then filesystem.makeDirectory(CONFIG_PATH) end
|
|
if (not filesystem.isDirectory(OUT_PATH)) then filesystem.makeDirectory(OUT_PATH) end
|
|
|
|
--default config
|
|
config = {
|
|
masterAccountCBdata = "",
|
|
masterAccountCreditPerAccount = 0,
|
|
newAccountCredit = 0,
|
|
sideChest = 1,
|
|
sideDrive = 5
|
|
}
|
|
|
|
--load the config if present
|
|
if (filesystem.exists(CONFIG_FILE) and not filesystem.isDirectory(CONFIG_FILE)) then
|
|
local cFile = io.open(CONFIG_FILE, "r")
|
|
assert(cFile, "Something went wrong when reading the config file")
|
|
local tconf = serialization.unserialize(cFile:read("*a")) or {}
|
|
cFile:close()
|
|
for key, val in pairs(tconf) do
|
|
config[key] = val --override default configurations
|
|
end
|
|
cFile:close()
|
|
end
|
|
|
|
--load masterAccountCBdata if present
|
|
if (config.masterAccountCBdata and config.masterAccountCBdata ~= "") then
|
|
---@type cardData
|
|
config.masterAccountCBdata = serialization.unserialize(data.decode64(config.masterAccountCBdata))
|
|
end
|
|
|
|
--register master cb on first boot
|
|
if (config.masterAccountCBdata == "") then
|
|
print("Insert master cb to register it")
|
|
local reader = libCB.waitForCB(5)
|
|
if (reader) then
|
|
local encryptedData = libCB.loadCB(reader)
|
|
local try = 0
|
|
local pin
|
|
repeat
|
|
try = try + 1
|
|
io.write("Enter pin : ")
|
|
pin = term.read(nil, nil, "*")
|
|
pin = pin:gsub("\n", "")
|
|
until (pin or try >= 3)
|
|
local cb = libCB.getCB(encryptedData, pin)
|
|
if (cb) then
|
|
config.masterAccountCBdata = cb
|
|
computer.beep()
|
|
else
|
|
---@diagnostic disable-next-line: assign-type-mismatch
|
|
config.masterAccountCBdata = nil
|
|
computer.beep()
|
|
computer.beep()
|
|
end
|
|
else
|
|
config.masterAccountCBdata = nil
|
|
computer.beep()
|
|
computer.beep()
|
|
end
|
|
end
|
|
|
|
saveConfig()
|
|
|
|
-- load already created account list
|
|
if (filesystem.exists(ACCOUNT_FILE)) then
|
|
local aFile = io.open(ACCOUNT_FILE, 'r')
|
|
assert(aFile, "No account file found. HOW !?")
|
|
for line in aFile:lines() do
|
|
line = string.gsub(line, " ", "")
|
|
line = parseCSVLine(line, ",")
|
|
table.insert(knownAccounts, {line[1], line[2]})
|
|
end
|
|
end
|
|
|
|
-- init screen
|
|
local old_res_x, old_res_y = gpu.getResolution()
|
|
gpu.setResolution(26, 13)
|
|
|
|
--listen for ctrl+c (interrupted)
|
|
event.listen("interrupted", function() run = false; return false end)
|
|
--MAIN LOOP====================================================================
|
|
while (run) do
|
|
term.clear()
|
|
print("Touch the screen")
|
|
print("to get a card")
|
|
local e, _, _, _, _, playerName = event.pull(1, "touch")
|
|
if (e) then
|
|
makeCard(playerName)
|
|
end
|
|
end
|
|
--restore old screen resolution
|
|
gpu.setResolution(old_res_x, old_res_y)
|