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

Keycard System?

Started by Kron, 30 April 2013 - 05:50 PM
Kron #1
Posted 30 April 2013 - 07:50 PM
Hey guys. I'm still new to lua. I have absolutely NO clue where to start with a keycard door. If anyone can please help me out with this, it would be amazing. Thanks.


-Kron
Kingdaro #2
Posted 30 April 2013 - 08:55 PM
Well, there are multiple ways you could go about doing this. The most secure way would be to have an authentication server but I won't be stepping there as it's complicated as balls and I honestly hate coding multi-program systems.

Here's something simple, each keycard is a disk drive and has a file on it called "key". This file contains the specific password needed to pass the door.

So if your password was just "something random", you need to first go to your computer, insert the disk into an attached disk drive, and edit the program "disk/key", then type in:

something random

in the editor, and save it.

Now for your keycard door, you could have a setup similar to this: http://imgur.com/modap5Z,TKaupHJ#0 (Make sure to view the second image.)

The monitor on top is there to tell the user whether their card was accepted or not. Onto the actual script, the entire basis of the script is simply looping forever, waiting for a "disk" event (which indicates that a disk was inserted into a drive), and reading the contents of the "key" file on the disk to check if it is the correct password, which in this case is "something random".

Spoiler

local password = "something random"
local monitor = peripheral.wrap('top')

while true do
	os.pullEvent('disk') -- "wait until a disk is inserted"
	
	-- "read the contents of the "key" file on the disk"
	-- "store it in the variable 'content'"
	local file = fs.open('disk/key', 'r')
	local content
	
	-- "only store the content if the file actually exists"
	if file then
		content = file.readAll()
		file.close()
	end
	
	-- "eject the disk after we're done"
	disk.eject('back') -- "'back' is just the side of the disk"
	
	-- "check the content against our password"
	-- "if it's right, turn on the redstone to open the door"
	-- "and flash the top monitor a lime green"
	if content == password then
		rs.setOutput('front', true)
		monitor.setBackgroundColor(colors.lime)
		monitor.clear() -- "monitor.clear sets the background to whatever the background color is"
		sleep(3) -- "allow the user to enter the room"
		
	-- "if the password is wrong, flash the monitor red"
	else
		monitor.setBackgroundColor(colors.red)
		monitor.clear()
		sleep(1)
	end
	
	-- "make sure the door is closed, and the monitor is black again"
	rs.setOutput('front', false)
	monitor.setBackgroundColor(colors.black)
	monitor.clear()
end

Uncommented and uncluttered:

Spoiler

local password = "something random"
local monitor = peripheral.wrap('top')

while true do
	os.pullEvent('disk')
	
	local file = fs.open('disk/key', 'r')
	local content
	if file then
		content = file.readAll()
		file.close()
	end
	
	disk.eject('back')

	if content == password then
		rs.setOutput('front', true)
		monitor.setBackgroundColor(colors.lime)
		monitor.clear()
		sleep(3)
	else
		monitor.setBackgroundColor(colors.red)
		monitor.clear()
		sleep(1)
	end

	rs.setOutput('front', false)
	monitor.setBackgroundColor(colors.black)
	monitor.clear()
end

Using this, if you insert a keycard with a "key" file in it with the correct password, you can go in. Otherwise, if it either has the wrong password or no key file at all, it gets rejected and spat back out at the user.
tonkku107 #3
Posted 04 May 2013 - 03:33 AM
Well, there are multiple ways you could go about doing this. The most secure way would be to have an authentication server but I won't be stepping there as it's complicated as balls and I honestly hate coding multi-program systems.

Here's something simple, each keycard is a disk drive and has a file on it called "key". This file contains the specific password needed to pass the door.

So if your password was just "something random", you need to first go to your computer, insert the disk into an attached disk drive, and edit the program "disk/key", then type in:

something random

in the editor, and save it.

Now for your keycard door, you could have a setup similar to this: http://imgur.com/modap5Z,TKaupHJ#0 (Make sure to view the second image.)

The monitor on top is there to tell the user whether their card was accepted or not. Onto the actual script, the entire basis of the script is simply looping forever, waiting for a "disk" event (which indicates that a disk was inserted into a drive), and reading the contents of the "key" file on the disk to check if it is the correct password, which in this case is "something random".

Spoiler

local password = "something random"
local monitor = peripheral.wrap('top')

while true do
	os.pullEvent('disk') -- "wait until a disk is inserted"
	
	-- "read the contents of the "key" file on the disk"
	-- "store it in the variable 'content'"
	local file = fs.open('disk/key', 'r')
	local content
	
	-- "only store the content if the file actually exists"
	if file then
		content = file.readAll()
		file.close()
	end
	
	-- "eject the disk after we're done"
	disk.eject('back') -- "'back' is just the side of the disk"
	
	-- "check the content against our password"
	-- "if it's right, turn on the redstone to open the door"
	-- "and flash the top monitor a lime green"
	if content == password then
		rs.setOutput('front', true)
		monitor.setBackgroundColor(colors.lime)
		monitor.clear() -- "monitor.clear sets the background to whatever the background color is"
		sleep(3) -- "allow the user to enter the room"
		
	-- "if the password is wrong, flash the monitor red"
	else
		monitor.setBackgroundColor(colors.red)
		monitor.clear()
		sleep(1)
	end
	
	-- "make sure the door is closed, and the monitor is black again"
	rs.setOutput('front', false)
	monitor.setBackgroundColor(colors.black)
	monitor.clear()
end

Uncommented and uncluttered:

Spoiler

local password = "something random"
local monitor = peripheral.wrap('top')

while true do
	os.pullEvent('disk')
	
	local file = fs.open('disk/key', 'r')
	local content
	if file then
		content = file.readAll()
		file.close()
	end
	
	disk.eject('back')

	if content == password then
		rs.setOutput('front', true)
		monitor.setBackgroundColor(colors.lime)
		monitor.clear()
		sleep(3)
	else
		monitor.setBackgroundColor(colors.red)
		monitor.clear()
		sleep(1)
	end

	rs.setOutput('front', false)
	monitor.setBackgroundColor(colors.black)
	monitor.clear()
end

Using this, if you insert a keycard with a "key" file in it with the correct password, you can go in. Otherwise, if it either has the wrong password or no key file at all, it gets rejected and spat back out at the user.
This is kinda old topic but i'm getting lock:2: Attempt to call nil
Kingdaro #4
Posted 04 May 2013 - 04:04 AM
Either you named a variable "peripheral" or misspelled the function call on line 2.
tonkku107 #5
Posted 04 May 2013 - 04:24 AM
Either you named a variable "peripheral" or misspelled the function call on line 2.

local monitor = peripheral.wrap('top')

copied and pasted: same error
Kingdaro #6
Posted 04 May 2013 - 05:08 AM
Huh. Well, the code worked when I tested it, so I'm not sure. Post your entire code.
tonkku107 #7
Posted 04 May 2013 - 07:34 AM
Huh. Well, the code worked when I tested it, so I'm not sure. Post your entire code.

local password = "cows"
local monitor = peripheral.warp('top')
while true do
os.pullEvent('disk')

local file = fs.open('disk/key', 'r')
local content
if file then
  content = file.readALL()
  file.close()
end

disk.eject('back')

if content == password then
  rs.setOutput('front', true)
  monitor.setBackroundColor(colors.lime)
  monitor.clear()
  sleep(3)
else
  monitor.setBackroundColor(colors.red)
  monitor.clear()
  sleep(1)
end

rs.setOutput('front', false)
monitor.setBackroundColor(colors.black)
monitor.clear()
end

Nevermind! warp, wrap typo… but how did the same typo go when i copypasted?

Now here comes bunch of questions:
1. Can it be done like no computers visible, only the drive, and with noteblocks?
Spoiler
2. Can i have that make a log to my pass server when there is an access easly without requiring that?
Spoiler>AccessServer

local myid = os.computerID()
local doorList = { 2,4,5,8 }
local passwordForDoor = { "minecraft","creeper","exit","slime" }
mon=peripheral.wrap("left")
print("Access Terminal")
rednet.open("top")

print("Computer id for Access Terminal is "..tostring(myid))
function findIndexForId(id)
   for i,v in ipairs(doorList) do
	  if id == v then
		 return i
	  end
   end
   return 0
end

--[[ for future implementation ]]--
function setPasswordForLock(id,password)
   local i = findIndexForId(id)
  
   if i == 0 then
	  return false
   end
  
   passwordForDoor[i] = password
   print("in setPasswordForLock"..id..password)
   return true
end
function checkPasswordForLock(id,password)
   local i = findIndexForId(id)
   if i == 0 then
	  return -1
   end
   if passwordForDoor[i] == password then
	  return 1
   else
	  return 0
   end
end
--[[ Not needed yet, for later when we allow remove password changes ]]--
function saveData()
  local myfile = io.open("/doorpw.dat","w")
  print(tostring(myfile))
  print("1")
  for i,pw in ipairs(passwordForDoor) do
	 myfile:write(pw)
  end
  print("4")
  myfile:close()
end

local isValid = 0
while true do
   local timeString = textutils.formatTime(os.time(),false)
   senderId, message, distance = rednet.receive()
	
   isValid = checkPasswordForLock(senderId, message)
   if isValid == -1 then
	  print("server "..senderId.." sent us a request but is not in our list")
	  rednet.send(senderId, "Not Listed")
	  mon.scroll(1)
	  mon.setCursorPos(1,4)
	  mon.write(senderId.." tried to connect at "..timeString)
   elseif isValid == 1 then
	  rednet.send(senderId, "Valid")
	  mon.scroll(1)
	  mon.setCursorPos(1,4)
	  mon.write("Access from "..senderId.." at "..timeString)
   else
	  rednet.send(senderId, "Not Valid")
	  mon.scroll(1)
	  mon.setCursorPos(1,4)
	  mon.write("Failure from "..senderId.." at "..timeString)
  end
end
AND could you help me understand those not yet implemented… for future parts?
Nah it was not a bunch…
Pharap #8
Posted 04 May 2013 - 08:51 AM
Now here comes bunch of questions:
1. Can it be done like no computers visible, only the drive, and with noteblocks?
Spoiler
2. Can i have that make a log to my pass server when there is an access easly without requiring that?
Spoiler>AccessServer

local myid = os.computerID()
local doorList = { 2,4,5,8 }
local passwordForDoor = { "minecraft","creeper","exit","slime" }
mon=peripheral.wrap("left")
print("Access Terminal")
rednet.open("top")

print("Computer id for Access Terminal is "..tostring(myid))
function findIndexForId(id)
   for i,v in ipairs(doorList) do
	  if id == v then
		 return i
	  end
   end
   return 0
end

--[[ for future implementation ]]--
function setPasswordForLock(id,password)
   local i = findIndexForId(id)
  
   if i == 0 then
	  return false
   end
  
   passwordForDoor[i] = password
   print("in setPasswordForLock"..id..password)
   return true
end
function checkPasswordForLock(id,password)
   local i = findIndexForId(id)
   if i == 0 then
	  return -1
   end
   if passwordForDoor[i] == password then
	  return 1
   else
	  return 0
   end
end
--[[ Not needed yet, for later when we allow remove password changes ]]--
function saveData()
  local myfile = io.open("/doorpw.dat","w")
  print(tostring(myfile))
  print("1")
  for i,pw in ipairs(passwordForDoor) do
	 myfile:write(pw)
  end
  print("4")
  myfile:close()
end

local isValid = 0
while true do
   local timeString = textutils.formatTime(os.time(),false)
   senderId, message, distance = rednet.receive()
	
   isValid = checkPasswordForLock(senderId, message)
   if isValid == -1 then
	  print("server "..senderId.." sent us a request but is not in our list")
	  rednet.send(senderId, "Not Listed")
	  mon.scroll(1)
	  mon.setCursorPos(1,4)
	  mon.write(senderId.." tried to connect at "..timeString)
   elseif isValid == 1 then
	  rednet.send(senderId, "Valid")
	  mon.scroll(1)
	  mon.setCursorPos(1,4)
	  mon.write("Access from "..senderId.." at "..timeString)
   else
	  rednet.send(senderId, "Not Valid")
	  mon.scroll(1)
	  mon.setCursorPos(1,4)
	  mon.write("Failure from "..senderId.." at "..timeString)
  end
end
AND could you help me understand those not yet implemented… for future parts?
Nah it was not a bunch…

1- Only if you hide the computer and use redstone to link to the door.
2- You can use modems to transmit data to your server and have the server log it, that would be no problem. You could also make it so that the passwords are stored on the server itself and make the door computer check with the server before letting people through. I cannot however vouch for the validity of your code.
tonkku107 #9
Posted 04 May 2013 - 08:54 AM
2- You can use modems to transmit data to your server and have the server log it, that would be no problem. You could also make it so that the passwords are stored on the server itself and make the door computer check with the server before letting people through. I cannot however vouch for the validity of your code.
I couldn't make it so that it could go without having to check the pass there. I just want to the computer to send the was it success or not to the computer and it will put it on the monitor.
Pharap #10
Posted 04 May 2013 - 12:47 PM
2- You can use modems to transmit data to your server and have the server log it, that would be no problem. You could also make it so that the passwords are stored on the server itself and make the door computer check with the server before letting people through. I cannot however vouch for the validity of your code.
I couldn't make it so that it could go without having to check the pass there. I just want to the computer to send the was it success or not to the computer and it will put it on the monitor.

You'll have to look into how to use modems. It should be as simple as sending a message from one computer and waiting for an event at the other, but I haven't used modems since the 1.5 upgrade, and haven't had time to memorise the new frequency system, so I'd suggest you look for a tutorial on using modems written for the 1.5 system. Sorry I can't help you with that bit, I have been very busy the past few months.
tonkku107 #11
Posted 05 May 2013 - 06:07 AM
2- You can use modems to transmit data to your server and have the server log it, that would be no problem. You could also make it so that the passwords are stored on the server itself and make the door computer check with the server before letting people through. I cannot however vouch for the validity of your code.
I couldn't make it so that it could go without having to check the pass there. I just want to the computer to send the was it success or not to the computer and it will put it on the monitor.

You'll have to look into how to use modems. It should be as simple as sending a message from one computer and waiting for an event at the other, but I haven't used modems since the 1.5 upgrade, and haven't had time to memorise the new frequency system, so I'd suggest you look for a tutorial on using modems written for the 1.5 system. Sorry I can't help you with that bit, I have been very busy the past few months.
I have already 3 computer sending the passwords to the "server" and "server" sending the computer is it valid or not.
And i know how i can get the computer send the password in it and get the valid or not valid
Pharap #12
Posted 05 May 2013 - 07:58 AM
You'll have to look into how to use modems. It should be as simple as sending a message from one computer and waiting for an event at the other, but I haven't used modems since the 1.5 upgrade, and haven't had time to memorise the new frequency system, so I'd suggest you look for a tutorial on using modems written for the 1.5 system. Sorry I can't help you with that bit, I have been very busy the past few months.
I have already 3 computer sending the passwords to the "server" and "server" sending the computer is it valid or not.
And i know how i can get the computer send the password in it and get the valid or not valid

So if you know how to open and close doors on a password and know how to transmit between modems, what's the bit you can't do?
tonkku107 #13
Posted 05 May 2013 - 08:51 AM
You'll have to look into how to use modems. It should be as simple as sending a message from one computer and waiting for an event at the other, but I haven't used modems since the 1.5 upgrade, and haven't had time to memorise the new frequency system, so I'd suggest you look for a tutorial on using modems written for the 1.5 system. Sorry I can't help you with that bit, I have been very busy the past few months.
I have already 3 computer sending the passwords to the "server" and "server" sending the computer is it valid or not.
And i know how i can get the computer send the password in it and get the valid or not valid

So if you know how to open and close doors on a password and know how to transmit between modems, what's the bit you can't do?
The code on the spoiler. It's too complicated for me. I wan't to get the "server" computer to NOT send back any valids and it won't need to be on the doorList…

local myid = os.computerID()
local doorList = { 2,4,5,8 } --[[ I don't want the door to be here but it would still accept it ]]--
local passwordForDoor = { "minecraft","creeper","exit","slime" } --[[ I don't wan't the password to be here either ]]--
mon=peripheral.wrap("left")
print("Access Terminal")
rednet.open("top")
print("Computer id for Access Terminal is "..tostring(myid))
function findIndexForId(id)
   for i,v in ipairs(doorList) do
		  if id == v then
				 return i
		  end
   end
   return 0
end
--[[ for future implementation ]]--
function setPasswordForLock(id,password)
   local i = findIndexForId(id)

   if i == 0 then
		  return false
   end

   passwordForDoor[i] = password
   print("in setPasswordForLock"..id..password)
   return true
end
function checkPasswordForLock(id,password)
   local i = findIndexForId(id)
   if i == 0 then
		  return -1
   end
   if passwordForDoor[i] == password then
		  return 1
   else
		  return 0
   end
end
--[[ Not needed yet, for later when we allow remove password changes ]]--
function saveData()
  local myfile = io.open("/doorpw.dat","w")
  print(tostring(myfile))
  print("1")
  for i,pw in ipairs(passwordForDoor) do
		 myfile:write(pw)
  end
  print("4")
  myfile:close()
end
local isValid = 0
while true do
   local timeString = textutils.formatTime(os.time(),false)
   senderId, message, distance = rednet.receive()
	  
   isValid = checkPasswordForLock(senderId, message)
   if isValid == -1 then
		  print("server "..senderId.." sent us a request but is not in our list")
		  rednet.send(senderId, "Not Listed")
		  mon.scroll(1)
		  mon.setCursorPos(1,4)
		  mon.write(senderId.." tried to connect at "..timeString)
   elseif isValid == 1 then
		  rednet.send(senderId, "Valid")
		  mon.scroll(1)
		  mon.setCursorPos(1,4)
		  mon.write("Access from "..senderId.." at "..timeString)
   else
		  rednet.send(senderId, "Not Valid")
		  mon.scroll(1)
		  mon.setCursorPos(1,4)
		  mon.write("Failure from "..senderId.." at "..timeString)
--[[ Here i want the computer to print: Access From IDHERE at TIMEHERE ]]--
  end
end
Look for comments! E: the thing is now all comments but whatever
I understand the monitor part but not the white-list
Pharap #14
Posted 05 May 2013 - 10:24 AM
I don't know if this is what you're after, but I had fun building it:
https://dl.dropboxus...KeyCardDoor.zip

It's a minecraft world demonstrating use of a simple high-security keycard system.

As for a whitelist, it just means that only computers with ids in the whitelist can contact the server.