This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
JamiePhonic's profile picture

[Tables] Tables Multiple Values Per Key

Started by JamiePhonic, 11 August 2013 - 08:24 AM
JamiePhonic #1
Posted 11 August 2013 - 10:24 AM
i'm writing an authentication program that stores a players username and password set by what the enter into an add user program. thing is, i intend to implement this into another program (the client side of my server computercraft mainframe) which works (currently) by entering a password which the server validates from variables directly in the code and sends back a command which is the name of a function in the client that displays the commands the player can use. for example, if the player enters "overlord" as the password, the server responds with "admin" which tells the client to run the admin menu, from which all the functions of the server can be accessed (frame doors, lights etc…)

what i want to do with this program is to handle all that outside the code.

the auth program i'm writing works as it is (user enters username an password into adduser program, which writes them to the password file. what i want to do is also store the menu they are allowed access to

it adds the username and password to a table on load, in the form [username] = password
what i want to do is to also add menu to the same key, like [username] = password, menu

is that possible?
darkrising #2
Posted 11 August 2013 - 10:39 AM
make username a table

username = {}
username.password = "thepassword"
username.menu = "menu key"
JamiePhonic #3
Posted 11 August 2013 - 10:50 AM
make username a table

username = {}
username.password = "thepassword"
username.menu = "menu key"
i dont understand (not very familiar with tables)

heres the code that writes to the file:

tPasswd={}
tPasswd[username]=password
local file = io.open(sPasswdPath,"w")
for user,pass in pairs(tPasswd) do
	file:write(user .. " " .. pass .."\n")
end
file:close()
username and password are variables that are collected earlier. i need a menu variable added to this so its written to file to
sPasswdPath is the name of the password file

EDIT: actually, i think i have a vague idea of what you mean @darkrising. i found some code from a previous project i was working on,


available_items = {
[1] = {item = "gold bar", quantity = 32, side = "right", color = "yellow"},
}
where: print(available_items[1].item ) would return "gold bar"

so adapted it would be

tPasswd = {
[Fred] = {password = "password", menu = "menu1"},
}
where: print(tPasswd[username]) would return "fred"
and: print(tPasswd[username].password) would return "password" No?
darkrising #4
Posted 11 August 2013 - 11:13 AM
With tables you pretty much have anything as a key, for example:

user = "fred"
database = {} -- our database table
database[user] = {} -- this is a table in a table so it could be also written like data.fred = {} 
database[user].password = "pass" 
database[user].menu = "menu key"
JamiePhonic #5
Posted 11 August 2013 - 11:44 AM
With tables you pretty much have anything as a key, for example:

user = "fred"
database = {} -- our database table
database[user] = {} -- this is a table in a table so it could be also written like data.fred = {}
database[user].password = "pass"
database[user].menu = "menu key"
still not getting you. heres the whole program.
it doesnt serialise the table before writing, it splits it into "username password" and writes that, an when reading, it takes that an sticks it into a table.
i know serialising it would be easier, i just dont know how to get there. the top function is the actual program, the bottom function is just to decide what happens. function returns the username and true if login is successful

function clear()
term.clear()
term.setCursorPos(1,1)
end
function doLogin() --returns true if login succeeds, false if it fails
local sPasswdPath = "ACCOUNTS.F"
--check we have a login path, if not, what we enter will create the account instead of log in
if fs.exists( sPasswdPath ) then--Password exists so this is not the first run
  local loginCount=0
  while loginCount < 3 do
   local tPasswd={}
   local file = fs.open(sPasswdPath,"r")
   local sLine = file:readLine()
   while sLine do
	for k, v in string.gmatch(sLine, "(%w+)%s(%w+)") do
	 tPasswd[k]=v
	end
	sLine = file:readLine()
   end
   file:close()
  
   local username,password="",""
   clear()
   print("terminal is locked. login.")
   write("username: ")
   username = read()
   print(tPasswd[username])
   write("password: ")
   password = read()
  
   if (tPasswd[username]==password) then --Login ok
	return username,true
   else --invalid login
	loginCount=loginCount+1
	print("Invalid login")
	sleep(1)
   end
  end
  return "",false

else--This is the first run, ask if they want to secure this box.
  clear()
  print("secure?")
  local sText = read()
  if (sText=="yes") then
   local passwordMatch=false
   local username,password,password2,menu="",""
   while not passwordMatch do
	write("username: ")
	username = read()
	write("password: ")
	password = read()
	write("password again: ")
	password2 = read()
	write("Menu: ")
	menu = read()
	if (password == password2) then
	 passwordMatch = true
	else
	 print("Passwords do not match")
	 sleep(1)
	end
   end
  --Our passwords match, store them for later.
  tPasswd={}
  tPasswd[username]=password
  local file = io.open(sPasswdPath,"w")
  for user,pass in pairs(tPasswd) do
   file:write(user .. " " .. pass .."\n")
  end
  file:close()
  return username,true

  else --Do not secure
   local file = io.open(sPasswdPath,"w")
   file:close()
   return "",true
  end
end
end
-- Do login code
function login()
local user, succ = doLogin() --calls doLogin in redowrks API (above because of how lua works)
if not succ then
  --Login failed
  term.clear()
  term.setCursorPos(1,5)
  print("login failed.\n\nLocking terminal for 15 seconds")
  local bExit=false
  os.startTimer(15)
  while not bExit do
   falt, sEvent, param = pcall(os.pullEvent)
   if sEvent == "timer" then
	bExit = true
   end
  end
  os.shutdown()
else
  print("logged in as: " .. user)
end
end
login()
darkrising #6
Posted 11 August 2013 - 11:56 AM
To store a table serialized just get a couple of functions:

function saveDB(tbl, filename)
  local str = textutils.serialize(tbl)
  local file = fs.open(filename, "w")
  file.write(str)
  file.close()
end
function loadDB(filename)
  local file = fs.open(filename, "r")
  local tbl = textutils.unserialize(file.readAll())
  file.close()
  return tbl
end

aTable = {"some values"}
saveDB(aTable, "filename")
aTable = loadDB("filename")


Something along those lines.
JamiePhonic #7
Posted 11 August 2013 - 12:29 PM
To store a table serialized just get a couple of functions:

function saveDB(tbl, filename)
  local str = textutils.serialize(tbl)
  local file = fs.open(filename, "w")
  file.write(str)
  file.close()
end
function loadDB(filename)
  local file = fs.open(filename, "r")
  local tbl = textutils.unserialize(file.readAll())
  file.close()
  return tbl
end

aTable = {"some values"}
saveDB(aTable, "filename")
aTable = loadDB("filename")


Something along those lines.
ok, we're getting somewhere now. i managed to implement those functions and have it work, but how do i now add the menu field?

Updated code:

function clear()
term.clear()
term.setCursorPos(1,1)
end
function saveDB(tbl, filename)
  local str = textutils.serialize(tbl)
  local file = fs.open(filename, "w")
  file.write(str)
  file.close()
end
function loadDB(filename)
  local file = fs.open(filename, "r")
  local tbl = textutils.unserialize(file.readAll())
  file.close()
  return tbl
end
aTable = {"some values"}
saveDB(aTable, "filename")
aTable = loadDB("filename")
function doLogin() --returns true if login succeeds, false if it fails
local PasswdDB = "ACCOUNTS.F"
--check we have a login path, if not, what we enter will create the account instead of log in
if fs.exists( PasswdDB ) then--Password exists so this is not the first run
  local loginCount=0
  while loginCount < 3 do
   local TableUsers=loadDB(PasswdDB)
  
   local username,password="",""
   clear()
   print("terminal is locked. login.")
   write("username: ")
   username = read()
   print(TableUsers[username])
   write("password: ")
   password = read()
  
   if (TableUsers[username]==password) then --Login ok
    return username,true
   else --invalid login
    loginCount=loginCount+1
    print("Invalid login")
    sleep(1)
   end
  end
  return "",false
 
else--This is the first run, ask if they want to secure this box.
  clear()
  print("secure?")
  local sText = read()
  if (sText=="yes") then
   local passwordMatch=false
   local username,password,password2,menu="",""
   while not passwordMatch do
    write("username: ")
    username = read()
    write("password: ")
    password = read()
    write("password again: ")
    password2 = read()
    write("Menu: ")
    menu = read()
    if (password == password2) then
	 passwordMatch = true
    else
	 print("Passwords do not match")
	 sleep(1)
    end
   end
  --Our passwords match, store them for later.
  TableUsers={}
  TableUsers[username]=password
  saveDB(TableUsers, PasswdDB)
  return username,true
 
  else --Do not secure
   local file = io.open(PasswdDB,"w")
   file:close()
   return "",true
  end
end
end
-- Do login code
function login()
local user, succ = doLogin() --calls doLogin in redowrks API (above because of how lua works)
if not succ then
  --Login failed
  term.clear()
  term.setCursorPos(1,5)
  print("login failed.\n\nLocking terminal for 15 seconds")
  local bExit=false
  os.startTimer(15)
  while not bExit do
   falt, sEvent, param = pcall(os.pullEvent)
   if sEvent == "timer" then
    bExit = true
   end
  end
  os.shutdown()
else
  print("logged in as: " .. user)
end
end
login()
darkrising #8
Posted 11 August 2013 - 12:55 PM
line 69:

	TableUsers={}
	TableUsers[username]= {}
	TableUsers[username].password = password
	TableUsers[username].menu = menu
	saveDB(TableUsers, PasswdDB)

Edit so line 35 would be

if (TableUsers[username].password == password) then --Login ok
JamiePhonic #9
Posted 11 August 2013 - 01:34 PM
line 69:

	TableUsers={}
	TableUsers[username]= {}
	TableUsers[username].password = password
	TableUsers[username].menu = menu
	saveDB(TableUsers, PasswdDB)

Edit so line 35 would be

if (TableUsers[username].password == password) then --Login ok
You sir, Are AWESOME!
i've realised that with a few minor tweaks, i can turn this into an API. if i get round to doing it, ill give you credit :-)
darkrising #10
Posted 11 August 2013 - 01:41 PM
line 69:

	TableUsers={}
	TableUsers[username]= {}
	TableUsers[username].password = password
	TableUsers[username].menu = menu
	saveDB(TableUsers, PasswdDB)

Edit so line 35 would be

if (TableUsers[username].password == password) then --Login ok
You sir, Are AWESOME!
i've realised that with a few minor tweaks, i can turn this into an API. if i get round to doing it, ill give you credit :-)

No problem, glad I could help :)/>

If you look at my DarkPrograms I use a similar method handling users and other information.
JamiePhonic #11
Posted 11 August 2013 - 04:16 PM
another question for you @darkrising…
i also have a program that creates new users and one that deletes users. the problem i'm having is that when i make a new user with the code you gave me, instead of appending it, it overwrites the whole table. i tried using table.insert, but that failed.
i also tried crushing

TableUsers[username] = {}
TableUsers[username].password = password
TableUsers[username].menu = menu
down to just

TableUsers[username] = {password = password, menu = menu}
but still no luck

Edit: never mind. worked it out from another post. i was using this code

function adduser(username, password, menu)
local PasswdDB = "ACCOUNTS.F"
local TableUsers = {}
if fs.exists( PasswdDB ) then
  print("File exists. Loading")
  local TableUsers=loadDB(PasswdDB)
end

TableUsers[username] = {password = password, menu = menu}
saveDB(TableUsers, PasswdDB)
print("User " .. username .. " has been created.")
end
not noticing that i was reading the table into a local variable, so when i attempt to use it to index the table outside that if, TableUsers has gone out of scope and is nil.
all fixed :-)