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

Terminate-safe DoubleLock

Started by jtdavis99, 02 March 2012 - 01:24 AM
jtdavis99 #1
Posted 02 March 2012 - 02:24 AM
Amateur Ctrl+T safe doublelock. Please post ways it can be improved! :unsure:/>/>


local status, input

term.clear()
term.setCursorPos(1,1)

password = "access" –Sets the password
print("Welcome to jdpowercool's double lock system!")
print("===============================================")
write("Enter your password: ")
status, input = pcall(read) –Input the password
if input == password then
print("Access granted.")
sleep(1.5)
term.clear() –Clearing the terminal, and…
term.setCursorPos(1,1) –…THEN setting the cursor position

else
term.clear() –Clearing the terminal, and…
term.setCursorPos(1,1) –…THEN setting the cursor position
print("Wrong password. Locking computer for 15 seconds…")
sleep(15)
os.shutdown()

end

Password = "doubleaccess"
write("Enter the second password. ")
status, Input = pcall(read) –Input the password

term.clear() –Clearing the terminal, and…
term.setCursorPos(1,1) –…THEN setting the cursor position
if Input == Password then
print("Welcome!")
rs.setOutput("left", true) –Change this and the setOutput to the side the door is on
sleep(2) –Pause for 2 seconds
rs.setOutput("left", false)
sleep(1)
os.shutdown()

else
print("Access Denied.") –If the input is incorrect!
sleep(2)
os.shutdown() –Shut down the computer
end –Ends if
FuzzyPurp #2
Posted 02 March 2012 - 12:25 PM
Doesn't look fully anti-Ctrl+T proof. I can probably terminate it while its printing or after.
Espen #3
Posted 02 March 2012 - 01:54 PM
Hey jtdavis99,
I threw together some lines of code to give you an idea for how you can make a scalable version of your multiple password program.
The core is this function (Explanation is at the top of the code):

-- Takes a table of passwords and checks them against user input.
-- Returns 'true' if all passwords were entered correctly.
-- Returns 'false' on first wrong input.
function checkPasswords( _tPasswordList )
  -- Make sure we got a table, throw an error otherwise.
  if type( _tPasswordList ) ~= "table" then
	error( "Table expected, got "..type( _tPasswordList ).."." )
  end

  -- Iterate through all passwords in the table and compare them to the user input.
  for n = 1, #_tPasswordList do
	write( "Password #"..n..": " )
	local sInput = read( "*" )
	
	-- As soon as one password is entered incorrectly we immediately return false.
	if sInput ~= _tPasswordList[n] then
	  return false
	end
  end

  -- If we come to this point then all passwords have been entered correctly.
  return true
end

As an example of how to use that code & how you can make read() - or any other function that makes use of os.pullEvent() - use os.pullEventRaw() instead of os.pullEvent(), add this code to the above (add it after the function!):

local tPasswords = { "secret", "letmein" }	-- Put your passwords in here.

local nativePullEvent = os.pullEvent	-- Backup os.pullEvent
os.pullEvent = os.pullEventRaw  -- Overwrite os.pullEvent with os.pullEventRaw
local ok, result = pcall( checkPasswords, tPasswords )
os.pullEvent = nativePullEvent  -- Restore os.pullEvent

if not ok then
  -- If ok is 'false' then checkPasswords threw an error and thus result will contain the error message.
  error( result )
elseif result then  -- If ok was 'true' then there was no error. That means we can now check result, which will contain either 'true' or 'false'.
  print( "nAll entered passwords were correct. B)/>/>" )
else
  print( "nWrong password entered! B)/>/>" )
end

From the above code, note these lines:

local nativePullEvent = os.pullEvent	-- Backup os.pullEvent
os.pullEvent = os.pullEventRaw  -- Overwrite os.pullEvent with os.pullEventRaw
-- Do something
os.pullEvent = nativePullEvent  -- Restore os.pullEvent
They backup the os.pullEvent function and overwrite it with os.pullEventRaw, the latter which won't listen for the 'terminate' event that e.g. CTRL+T produces. After it has fulfilled its purpose I restore it, or else os.pullEvent would stay os.pullEventRaw for all other programs as well! At least until the next reboot.
This is because we overwrite a global variable in order to make read() or sleep() not stop at CTRL+T.

Instead of doing it this way you could just as well copy the read() function out of the 'bios.lua', replace the os.pullEvent call there with an os.pullEventRaw call. That might be a lot safer, but then you'd have an additional, big function to which only three letters have been added (namely: Raw ).
It's entirely up to you.

There are many ways to skin a cat, right? :unsure:/>/>

EDIT: Clarified the comment in the code line 'elseif result then'.
Edited on 02 March 2012 - 01:03 PM
Shade25 #4
Posted 02 March 2012 - 05:22 PM
As an example of how to use that code & how you can make read() - or any other function that makes use of os.pullEvent() - use os.pullEventRaw() instead of os.pullEvent(), add this code to the above (add it after the function!):

local nativePullEvent = os.pullEvent	-- Backup os.pullEvent
os.pullEvent = os.pullEventRaw  -- Overwrite os.pullEvent with os.pullEventRaw
-- Do something
os.pullEvent = nativePullEvent  -- Restore os.pullEvent
They backup the os.pullEvent function and overwrite it with os.pullEventRaw, the latter which won't listen for the 'terminate' event that e.g. CTRL+T produces. After it has fulfilled its purpose I restore it, or else os.pullEvent would stay os.pullEventRaw for all other programs as well! At least until the next reboot.
This is because we overwrite a global variable in order to make read() or sleep() not stop at CTRL+T.

Instead of doing it this way you could just as well copy the read() function out of the 'bios.lua', replace the os.pullEvent call there with an os.pullEventRaw call. That might be a lot safer, but then you'd have an additional, big function to which only three letters have been added (namely: Raw ).
It's entirely up to you.

There are many ways to skin a cat, right? :unsure:/>/>

EDIT: Clarified the comment in the code line 'elseif result then'.

Would another option besides overwriting base code be essentially just to run his sleep calls (since he already has his read calls going through pcall) through pcall as well?

Something along the lines of:

local pass = "test1"
local pass2 = "test2"

term.clear()
term.setCursorPos(1,1)

-- Start program and first password chek
print("Welcome to jdpowercool's double lock system!")
print("===============================================")
write("Enter your password: ")
local state,input = pcall(read,"*") -- Pet peeve is password readers not starring the input, security risks and all
if (input == pass) then
	print("Access granted.")
	state = pcall(sleep,1)
	term.clear()
	term.setCursorPos(1,1)
else
	term.clear()
	term.setCursorPos(1,1)
	print("Wrong password.  Locking computer for 15 seconds..")
	state = pcall(sleep,15)
	os.shutdown()
end

--Start second password check
write("Enter the second password. ")
state, input = pcall(read,"*")
term.clear()
term.setCursorPos(1,1)
if (input == pass2) then
	print("Welcome!")
	rs.setOutput("left",true)
	state = pcall(sleep,2)
	rs.setOutput("left",false)
	state = pcall(sleep,1)
	os.shutdown()	
else
	print("Access Denied")
	state = pcall(sleep,2)
	os.shutdown()
end
Drycode off the top of my head with trying to keep his code intact as much as possible, but something along those lines? Would also let them do ifchecks if someone tried to terminate and print a message about it or run other code.

Edit: If they were going to stay with that anyway, instead of using something along the lines of your posted scalable version. Just for something simple like that, since the base code replacement would probably be easier for large code which makes more frequent calls to os.pullEvent()
jtdavis99 #5
Posted 02 March 2012 - 06:11 PM
I have a question. I'm an amateur programmer and I'm still learning lua, why do people always use local? I don't understand what it does. Also, thanks for the feedback and additions :unsure:/>/>
Liraal #6
Posted 02 March 2012 - 06:17 PM
local is for creating a variable accessible only from within the function so that they don't mess up all your code by turning up where you'd least expect them. Just use local, okay? :unsure:/>/>
jtdavis99 #7
Posted 02 March 2012 - 06:18 PM
local is for creating a variable accessible only from within the function so that they don't mess up all your code by turning up where you'd least expect them. Just use local, okay? :unsure:/>/>

Well, yes, but where do I put them? Behind variables I know, but I've seen them behind random, simple programs =/
Liraal #8
Posted 02 March 2012 - 06:26 PM
it's more like in front of the variables :unsure:/>/>
But a 'local' function is basically the same thing: only accessible from within the file it's in.
Shade25 #9
Posted 02 March 2012 - 08:04 PM
If you've ever worked with javascript its pretty much the same as var, to give a javascript example:

function testStuff() {
var testVar = true
}

if (testVar == true) { print("TestVar is true") } else { print("TestVar is false") }

with the var, testVar is local so the if check will say its false, if you just did testVar = true instead of var testVar = true, then it would be global, so the ifcheck would say it was true.

So technically you can write all your code just by doing var = something, but its a much better programming practice to use local variables (local in lua). At the very least it makes it so you don't have to worry about overwriting variables in different functions by accident.

Edit: for a lua example (sorry more used to javascript, which is thankfully very similar to lua)

function testStuff()
local testVar = true
end

if (testVar == true) then print("TestVar is true") else print("TestVar is false") end
Espen #10
Posted 03 March 2012 - 07:37 PM
Would another option besides overwriting base code be essentially just to run his sleep calls (since he already has his read calls going through pcall) through pcall as well?

Using pcall() on sleep() only prevents errors occurring within sleep() to terminate the program that called it.
sleep() is still using os.pullEvent() though, which still listens for the 'terminate' event.
That means that if you hit CTRL+T during a sleep(), then the sleep timer will stop and return the error to pcall().

Example:

while true do
	local ok, errMsg = pcall( sleep, 10 )
	print("Hello World")
end

This would normally sleep 10 seconds and then print "Hello World", indefinitely.
But if, during the 10 seconds sleep, you'd press CTRL+T, then you would create a terminate event within sleep().
And since the os.pullEvent() that sleep() makes use of throws an error on this event, we'll immediately return to pcall.
I.e. ok will be 'false' and errMsg will contain the error message, which will be "Terminated".
Then "Hello World" will be printed, we loop back, and the 10 seconds sleep start again.

So as you can see, as long as sleep() is using os.pullEvent() we can interrupt it. The same goes for the read() function.
That's why I showed an example of how you can temporarily force os.pullEventRaw() to be used instead of os.pullEvent().
Or alternatively you could just copy the read() and/or sleep() function and adjust their code by changing their os.pullEvent() to os.pullEventRaw().

Because sleep() is a relatively small function, here an example with it:
Original sleep():
Spoiler

function sleep( _nTime )
	local timer = os.startTimer( _nTime )
	repeat
		local sEvent, param = os.pullEvent( "timer" )
	until param == timer
end
Modified sleep() to prevent the 'terminate' event:
Spoiler

function sleep( _nTime )
	local timer = os.startTimer( _nTime )
	repeat
		local sEvent, param = os.pullEventRaw( "timer" )
	until param == timer
end

With this modified sleep() function we now don't have to use pcall at all:

while true do
	sleep( 10 )
	print("Hello World")
end

You won't be able to stop sleep() now with CTRL+T.
The moment you add something like read() or similar though, then you stand before the same problem again.

To sum it up:
If you use functions that make use of os.pullEvent(), then you either temporarily overwrite os.pullEvent with os.pullEventRaw, or you copy the functions, modify them and then use these copies instead. :unsure:/>/>

P.S.: Sorry for the delayed answer.^^
elcid534 #11
Posted 15 March 2012 - 12:33 PM
Instead of doing it this way you could just as well copy the read() function out of the 'bios.lua', replace the os.pullEvent call there with an os.pullEventRaw call. That might be a lot safer, but then you'd have an additional, big function to which only three letters have been added (namely: Raw ).
It's entirely up to you.
now i'm no lua programmer but what if you created a copy of Read() then modify it to use os.pullEventRaw and call it ReadRaw()?
then you don't need to add the four lines of code to any lock on you minecraft/server. just have to call ReadRaw().
also possible api here called antiTerminate api that just adds the ReadRaw without modding the bios.
if someone is going to do that(because i suck at lua) plz just add my name somewhere in it.

edit: also create a SleepRaw() program
Espen #12
Posted 15 March 2012 - 12:46 PM
Instead of doing it this way you could just as well copy the read() function out of the 'bios.lua', replace the os.pullEvent call there with an os.pullEventRaw call. That might be a lot safer, but then you'd have an additional, big function to which only three letters have been added (namely: Raw ).
It's entirely up to you.
now i'm no lua programmer but what if you created a copy of Read() then modify it to use os.pullEventRaw and call it ReadRaw()?
then you don't need to add the four lines of code to any lock on you minecraft/server. just have to call ReadRaw().
also possible api here called antiTerminate api that just adds the ReadRaw without modding the bios.
if someone is going to do that(because i suck at lua) plz just add my name somewhere in it.

edit: also create a SleepRaw() program
Uhm… please read my quote within your post again, slowly and carefully. :D/>/>
Laserman34170 #13
Posted 26 July 2012 - 08:53 PM
Just add this to the first line and it will automatically use os.pullEventRaw() instead of os.pullEvent() at all times.

os.pullEvent = os.pullEventRaw
-- Copy this EXACTLY, and you will be protected
-- I always use this and it saves lots of time